Skip to content

Commit ff84a87

Browse files
authored
Merge pull request #66 from devlucky/feature/JSONAPIRelationships
Feature/jsonapi relationships
2 parents 0427396 + b9918bf commit ff84a87

14 files changed

+605
-49
lines changed

Kakapo.xcodeproj/project.pbxproj

+19-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88

99
/* Begin PBXBuildFile section */
1010
5B16AF891A00E1CEB873C5F8 /* Pods_Kakapo_iOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1250C40FD2117CD20E6AE31F /* Pods_Kakapo_iOSTests.framework */; };
11+
8BE0FC801D16BD9A00FE706A /* JSONAPILinksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC7E1D16BD8300FE706A /* JSONAPILinksTests.swift */; };
12+
8BE0FC811D16BD9B00FE706A /* JSONAPILinksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC7E1D16BD8300FE706A /* JSONAPILinksTests.swift */; };
13+
8BE0FC821D16BD9C00FE706A /* JSONAPILinksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC7E1D16BD8300FE706A /* JSONAPILinksTests.swift */; };
14+
8BE0FC841D172EC900FE706A /* JSONAPILinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC831D172EC900FE706A /* JSONAPILinks.swift */; };
15+
8BE0FC851D172EC900FE706A /* JSONAPILinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC831D172EC900FE706A /* JSONAPILinks.swift */; };
16+
8BE0FC861D172EC900FE706A /* JSONAPILinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC831D172EC900FE706A /* JSONAPILinks.swift */; };
17+
8BE0FC871D172EC900FE706A /* JSONAPILinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BE0FC831D172EC900FE706A /* JSONAPILinks.swift */; };
1118
AC9577F342F6730725CC9D72 /* Pods_Kakapo_tvOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C67882333142806D5CF9A918 /* Pods_Kakapo_tvOSTests.framework */; };
1219
D5363674ABF8735A0A1368BD /* Pods_Kakapo_macOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABE4F11D5A141DB87CD81023 /* Pods_Kakapo_macOSTests.framework */; };
1320
DE76E1311D0DC62B009721A4 /* Kakapo.h in Headers */ = {isa = PBXBuildFile; fileRef = DE76E0FA1D0DC37E009721A4 /* Kakapo.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -103,6 +110,8 @@
103110
/* Begin PBXFileReference section */
104111
1250C40FD2117CD20E6AE31F /* Pods_Kakapo_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Kakapo_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
105112
822EBBB73B6B4117D229CDF1 /* Pods-Kakapo tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Kakapo tvOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Kakapo tvOSTests/Pods-Kakapo tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
113+
8BE0FC7E1D16BD8300FE706A /* JSONAPILinksTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONAPILinksTests.swift; sourceTree = "<group>"; };
114+
8BE0FC831D172EC900FE706A /* JSONAPILinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONAPILinks.swift; sourceTree = "<group>"; };
106115
ABE4F11D5A141DB87CD81023 /* Pods_Kakapo_macOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Kakapo_macOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
107116
C67882333142806D5CF9A918 /* Pods_Kakapo_tvOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Kakapo_tvOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
108117
C9E9EAD776E83C0F5785A0DB /* Pods-Kakapo macOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Kakapo macOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Kakapo macOSTests/Pods-Kakapo macOSTests.debug.xcconfig"; sourceTree = "<group>"; };
@@ -261,21 +270,23 @@
261270
DE76E0FD1D0DC38B009721A4 /* Tests */ = {
262271
isa = PBXGroup;
263272
children = (
273+
DE76E0FE1D0DC38B009721A4 /* Info.plist */,
274+
8BE0FC7E1D16BD8300FE706A /* JSONAPILinksTests.swift */,
264275
DE76E1B11D0DC857009721A4 /* JSONAPITests.swift */,
265276
DE76E1B21D0DC857009721A4 /* KakapoDBTests.swift */,
266277
DE76E1B31D0DC857009721A4 /* PropertyPolicyTests.swift */,
267278
DE76E1B41D0DC857009721A4 /* RouterTests.swift */,
268279
DE76E1B51D0DC857009721A4 /* SerializerTests.swift */,
269280
DE76E1B61D0DC857009721A4 /* URLDecomposerTests.swift */,
270281
DE76E1B71D0DC857009721A4 /* XCTestCase+CustomAssertions.swift */,
271-
DE76E0FE1D0DC38B009721A4 /* Info.plist */,
272282
);
273283
path = Tests;
274284
sourceTree = "<group>";
275285
};
276286
DE76E1001D0DC395009721A4 /* Source */ = {
277287
isa = PBXGroup;
278288
children = (
289+
8BE0FC831D172EC900FE706A /* JSONAPILinks.swift */,
279290
DE76E1011D0DC395009721A4 /* JSONAPISerializer.swift */,
280291
DE76E1021D0DC395009721A4 /* KakapoDB.swift */,
281292
DE76E1031D0DC395009721A4 /* KakapoServer.swift */,
@@ -717,6 +728,7 @@
717728
DE76E19A1D0DC755009721A4 /* PropertyPolicy.swift in Sources */,
718729
DE76E19D1D0DC755009721A4 /* URLDecomposer.swift in Sources */,
719730
DE76E1971D0DC755009721A4 /* KakapoDB.swift in Sources */,
731+
8BE0FC851D172EC900FE706A /* JSONAPILinks.swift in Sources */,
720732
DE76E19C1D0DC755009721A4 /* Serializer.swift in Sources */,
721733
DE76E1961D0DC755009721A4 /* JSONAPISerializer.swift in Sources */,
722734
DE76E19B1D0DC755009721A4 /* Router.swift in Sources */,
@@ -733,6 +745,7 @@
733745
DE76E1921D0DC755009721A4 /* PropertyPolicy.swift in Sources */,
734746
DE76E1951D0DC755009721A4 /* URLDecomposer.swift in Sources */,
735747
DE76E18F1D0DC755009721A4 /* KakapoDB.swift in Sources */,
748+
8BE0FC861D172EC900FE706A /* JSONAPILinks.swift in Sources */,
736749
DE76E1941D0DC755009721A4 /* Serializer.swift in Sources */,
737750
DE76E18E1D0DC755009721A4 /* JSONAPISerializer.swift in Sources */,
738751
DE76E1931D0DC755009721A4 /* Router.swift in Sources */,
@@ -746,6 +759,7 @@
746759
buildActionMask = 2147483647;
747760
files = (
748761
DE76E1BC1D0DC857009721A4 /* JSONAPITests.swift in Sources */,
762+
8BE0FC811D16BD9B00FE706A /* JSONAPILinksTests.swift in Sources */,
749763
DE76E1CB1D0DC857009721A4 /* URLDecomposerTests.swift in Sources */,
750764
DE76E1BF1D0DC857009721A4 /* KakapoDBTests.swift in Sources */,
751765
DE76E1C81D0DC857009721A4 /* SerializerTests.swift in Sources */,
@@ -763,6 +777,7 @@
763777
DE76E18A1D0DC754009721A4 /* PropertyPolicy.swift in Sources */,
764778
DE76E18D1D0DC754009721A4 /* URLDecomposer.swift in Sources */,
765779
DE76E1871D0DC754009721A4 /* KakapoDB.swift in Sources */,
780+
8BE0FC871D172EC900FE706A /* JSONAPILinks.swift in Sources */,
766781
DE76E18C1D0DC754009721A4 /* Serializer.swift in Sources */,
767782
DE76E1861D0DC754009721A4 /* JSONAPISerializer.swift in Sources */,
768783
DE76E18B1D0DC754009721A4 /* Router.swift in Sources */,
@@ -776,6 +791,7 @@
776791
buildActionMask = 2147483647;
777792
files = (
778793
DE76E1BD1D0DC857009721A4 /* JSONAPITests.swift in Sources */,
794+
8BE0FC821D16BD9C00FE706A /* JSONAPILinksTests.swift in Sources */,
779795
DE76E1CC1D0DC857009721A4 /* URLDecomposerTests.swift in Sources */,
780796
DE76E1C01D0DC857009721A4 /* KakapoDBTests.swift in Sources */,
781797
DE76E1C91D0DC857009721A4 /* SerializerTests.swift in Sources */,
@@ -793,6 +809,7 @@
793809
DE76E1A21D0DC756009721A4 /* PropertyPolicy.swift in Sources */,
794810
DE76E1A51D0DC756009721A4 /* URLDecomposer.swift in Sources */,
795811
DE76E19F1D0DC756009721A4 /* KakapoDB.swift in Sources */,
812+
8BE0FC841D172EC900FE706A /* JSONAPILinks.swift in Sources */,
796813
DE76E1A41D0DC756009721A4 /* Serializer.swift in Sources */,
797814
DE76E19E1D0DC756009721A4 /* JSONAPISerializer.swift in Sources */,
798815
DE76E1A31D0DC756009721A4 /* Router.swift in Sources */,
@@ -806,6 +823,7 @@
806823
buildActionMask = 2147483647;
807824
files = (
808825
DE76E1BB1D0DC857009721A4 /* JSONAPITests.swift in Sources */,
826+
8BE0FC801D16BD9A00FE706A /* JSONAPILinksTests.swift in Sources */,
809827
DE76E1CA1D0DC857009721A4 /* URLDecomposerTests.swift in Sources */,
810828
DE76E1BE1D0DC857009721A4 /* KakapoDBTests.swift in Sources */,
811829
DE76E1C71D0DC857009721A4 /* SerializerTests.swift in Sources */,

Source/JSONAPILinks.swift

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//
2+
// JSONAPILinks.swift
3+
// Kakapo
4+
//
5+
// Created by Joan Romano on 19/06/16.
6+
// Copyright © 2016 devlucky. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/**
12+
* An enum representing JSON API Link types.
13+
14+
* A link MUST be represented as either:
15+
16+
- A string containing the link’s URL.
17+
- An object which can contain the following members:
18+
- `href`: a string containing the link’s URL.
19+
- `meta`: a meta object containing non-standard meta-information about the link.
20+
21+
* [See the JSON API documentation on links](http://jsonapi.org/format/#document-links)
22+
*/
23+
public enum JSONAPILink: CustomSerializable {
24+
case Simple(value: String)
25+
case Object(href: String, meta: Serializable)
26+
27+
public func customSerialize() -> AnyObject? {
28+
switch self {
29+
case let Object(href, meta):
30+
var serializedObject: [String: AnyObject] = ["href" : href]
31+
serializedObject["meta"] = meta.serialize()
32+
33+
return serializedObject
34+
case let Simple(value):
35+
return value
36+
}
37+
}
38+
}
39+
40+
/**
41+
* A protocol representing a JSON API entity with links. This will handle all different `links` combinations:
42+
43+
- Inside `data` field
44+
- Inside `included` field
45+
- Inside `relationships` field
46+
47+
* For the first two options, an entity must use the `links` property. In order to add links in the `relationships` field,
48+
an entity must use `relationshipsLinks` property and return them for every relationship. For example, given the representation:
49+
50+
```swift
51+
struct Cat: JSONAPIEntity, JSONAPILinkedEntity {
52+
let id: String
53+
let name: String
54+
let links: [String : JSONAPILink]?
55+
}
56+
57+
struct Dog: JSONAPIEntity, JSONAPILinkedEntity {
58+
let id: String
59+
let name: String
60+
let links: [String : JSONAPILink]?
61+
}
62+
63+
struct User: JSONAPIEntity, JSONAPILinkedEntity {
64+
let id: String
65+
let name: String
66+
let cats: [Cat]
67+
let links: [String : JSONAPILink]?
68+
let relationshipsLinks: [String : [String : JSONAPILink]]?
69+
}
70+
```
71+
72+
Appart from their own entity links, and in order to provide extra links for relationships, `User` must specify them for each relationship key:
73+
74+
```swift
75+
let cats = [Cat(id: "33", name: "Stancho", links: nil),
76+
Cat(id: "44", name: "Hez", links: ["test": JSONAPILink.Simple(value: "hello"),
77+
"another": JSONAPILink.Object(href: "http://example.com/articles/1/comments", meta: Meta())])]
78+
79+
let dog = Dog(id: "22", name: "Joan", links: nil)
80+
81+
let user = User(id: "11", name: "Alex", dog: dog, cats: cats,
82+
links: ["one": JSONAPILink.Simple(value: "hello"),
83+
"two": JSONAPILink.Object(href: "hello", meta: Meta())],
84+
relationshipsLinks: ["cats": ["prev": JSONAPILink.Simple(value: "hello"),
85+
"next": JSONAPILink.Simple(value: "world"),
86+
"first": JSONAPILink.Simple(value: "yeah"),
87+
"last": JSONAPILink.Simple(value: "text")],
88+
"dog": ["testDog": JSONAPILink.Simple(value: "hello"),
89+
"anotherDog": JSONAPILink.Object(href: "http://example.com/articles/1/comments", meta: Meta())]
90+
]
91+
)
92+
```
93+
94+
* In order to represent the top level links of the root object, check out `JSONAPISerializer` initialization methods.
95+
96+
* [See the JSON API documentation on links](http://jsonapi.org/format/#document-links)
97+
*/
98+
public protocol JSONAPILinkedEntity {
99+
var links: [String : JSONAPILink]? { get }
100+
var relationshipsLinks: [String : [String : JSONAPILink]]? { get }
101+
}
102+
103+
extension JSONAPILinkedEntity {
104+
public var links: [String : JSONAPILink]? { return nil }
105+
public var relationshipsLinks: [String : [String : JSONAPILink]]? { return nil }
106+
}

0 commit comments

Comments
 (0)