Skip to content

Commit 063535e

Browse files
author
Josh Holtz
committed
Merge pull request #35 from artcom/master
Improved resource parsing
2 parents ccf872c + 6e4365c commit 063535e

9 files changed

+80
-46
lines changed

Classes/JSONAPI.m

+31-25
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ - (void)inflateWithDictionary:(NSDictionary*)dictionary {
158158
// Parse errors
159159
if (dictionary[@"errors"]) {
160160
NSMutableArray *errors = [[NSMutableArray alloc] init];
161-
NSLog(@"ERRORS - %@", dictionary[@"errors"]);
161+
// NSLog(@"ERRORS - %@", dictionary[@"errors"]);
162162
for (NSDictionary *data in dictionary[@"errors"]) {
163163

164164
JSONAPIErrorResource *resource = [[JSONAPIErrorResource alloc] initWithDictionary: data];
165-
NSLog(@"Error resource - %@", resource);
165+
// NSLog(@"Error resource - %@", resource);
166166
if (resource) [errors addObject:resource];
167167
}
168168
_errors = errors;
@@ -171,32 +171,38 @@ - (void)inflateWithDictionary:(NSDictionary*)dictionary {
171171

172172
- (void)inflateWithResource:(NSObject <JSONAPIResource> *)resource
173173
{
174-
NSMutableArray *resourceArray = [[NSMutableArray alloc] init];
175-
[resourceArray addObject:resource];
176-
_resources = resourceArray;
174+
_resources = @[resource];
177175

178-
NSMutableDictionary *newDictionary = [[NSMutableDictionary alloc] init];
176+
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
177+
dictionary[@"data"] = [JSONAPIResourceParser dictionaryFor:resource];
179178

180-
newDictionary[@"data"] = [JSONAPIResourceParser dictionaryFor:resource];
181-
182-
NSArray *included = [JSONAPIResourceParser relatedResourcesFor:resource];
183-
if (included.count) {
184-
newDictionary[@"included"] = included;
185-
186-
NSMutableDictionary *includedResources = [[NSMutableDictionary alloc] init];
187-
for (NSObject <JSONAPIResource> *linked in included) {
188-
189-
JSONAPIResourceDescriptor *desc = [[linked class] descriptor];
190-
191-
NSMutableDictionary *typeDict = includedResources[desc.type] ?: @{}.mutableCopy;
192-
typeDict[linked.ID] = resource;
193-
194-
includedResources[desc.type] = typeDict;
195-
}
196-
_includedResources = includedResources;
179+
NSArray *relatedResources = [JSONAPIResourceParser relatedResourcesFor:resource];
180+
if (relatedResources.count) {
181+
_includedResources = [self mapIncludedResources:relatedResources forResource:resource];
182+
dictionary[@"included"] = [self parseRelatedResources:relatedResources];
197183
}
198-
199-
_dictionary = newDictionary;
184+
_dictionary = dictionary;
185+
}
186+
187+
- (NSDictionary *)mapIncludedResources:(NSArray *)relatedResources forResource:(NSObject <JSONAPIResource> *)resource
188+
{
189+
NSMutableDictionary *includedResources = [NSMutableDictionary new];
190+
for (NSObject <JSONAPIResource> *linked in relatedResources) {
191+
JSONAPIResourceDescriptor *desc = [[linked class] descriptor];
192+
NSMutableDictionary *typeDict = includedResources[desc.type] ?: @{}.mutableCopy;
193+
typeDict[linked.ID] = resource;
194+
includedResources[desc.type] = typeDict;
195+
}
196+
return includedResources;
197+
}
198+
199+
- (NSArray *)parseRelatedResources:(NSArray *)relatedResources
200+
{
201+
NSMutableArray *parsedResources = [NSMutableArray new];
202+
for (NSObject <JSONAPIResource> *linked in relatedResources) {
203+
[parsedResources addObject:[JSONAPIResourceParser dictionaryFor:linked]];
204+
}
205+
return parsedResources;
200206
}
201207

202208
@end

Classes/JSONAPIResourceDescriptor.h

+10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
*/
3131
@property (strong) NSString *idProperty;
3232

33+
@property (strong) NSString *selfLinkProperty;
34+
3335
/**
3436
* JSON-API "id" optional format.
3537
*
@@ -95,6 +97,14 @@
9597
*/
9698
- (void)addProperty:(NSString*)name;
9799

100+
/**
101+
* Add a simple property with custom json name.
102+
*
103+
* @param name The name of the property in the class.
104+
* @param jsonName The label of the property in JSON.
105+
*/
106+
- (void)addProperty:(NSString*)name withJsonName:(NSString *)json;
107+
98108
/**
99109
* Add a simple property with custom transform object.
100110
*

Classes/JSONAPIResourceDescriptor.m

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ - (void)addProperty:(NSString*)name {
5353
[self addProperty:name withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:name]];
5454
}
5555

56+
- (void)addProperty:(NSString*)name withJsonName:(NSString *)json
57+
{
58+
[self addProperty:name withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:json]];
59+
}
60+
5661
- (void)addProperty:(NSString*)name withDescription:(JSONAPIPropertyDescriptor*)description {
5762
[[self properties] setValue:description forKey:name];
5863
}

Classes/JSONAPIResourceParser.m

+9-8
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ + (void)set:(NSObject <JSONAPIResource> *)resource withDictionary:dictionary {
180180

181181
NSDictionary *relationships = [dictionary objectForKey:@"relationships"];
182182
NSDictionary *attributes = [dictionary objectForKey:@"attributes"];
183+
NSDictionary *links = [dictionary objectForKey:@"links"];
183184

184185
id ID = [dictionary objectForKey:@"id"];
185186
NSFormatter *format = [descriptor idFormatter];
@@ -191,6 +192,11 @@ + (void)set:(NSObject <JSONAPIResource> *)resource withDictionary:dictionary {
191192
} else {
192193
[resource setValue:ID forKey:[descriptor idProperty]];
193194
}
195+
196+
if (descriptor.selfLinkProperty) {
197+
NSString *selfLink = links[@"self"];
198+
[resource setValue:selfLink forKey:descriptor.selfLinkProperty];
199+
}
194200

195201
// Loops through all keys to map to properties
196202
NSDictionary *properties = [descriptor properties];
@@ -332,20 +338,15 @@ + (NSArray*)relatedResourcesFor:(NSObject <JSONAPIResource>*)resource {
332338
NSDictionary *properties = [descriptor properties];
333339
for (NSString *key in properties) {
334340
JSONAPIPropertyDescriptor *property = [properties objectForKey:key];
335-
336341
if (property.resourceType) {
337-
id value = [self valueForKey:key];
342+
id value = [resource valueForKey:key];
338343
if ([value isKindOfClass:[NSArray class]]) {
339-
for (NSObject <JSONAPIResource> *element in value) {
340-
[related addObject:[JSONAPIResourceParser dictionaryFor:element]];
341-
}
344+
[related addObjectsFromArray:value];
342345
} else {
343-
NSObject <JSONAPIResource> *attribute = value;
344-
[related addObject:[JSONAPIResourceParser dictionaryFor:attribute]];
346+
[related addObject:value];
345347
}
346348
}
347349
}
348-
349350
return related;
350351
}
351352

Project/JSONAPI/ArticleResource.m

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ + (JSONAPIResourceDescriptor*)descriptor {
2626
__descriptor = [[JSONAPIResourceDescriptor alloc] initWithClass:[self class] forLinkedType:@"articles"];
2727

2828
[__descriptor setIdProperty:@"ID"];
29+
[__descriptor setSelfLinkProperty:@"selfLink"];
2930

3031
[__descriptor addProperty:@"title"];
3132
[__descriptor addProperty:@"date"

Project/JSONAPI/CommentResource.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ + (JSONAPIResourceDescriptor*)descriptor {
2525

2626
[__descriptor setIdProperty:@"ID"];
2727

28-
[__descriptor addProperty:@"text" withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:@"body"]];
28+
[__descriptor addProperty:@"text" withJsonName:@"body"];
2929

3030
[__descriptor hasOne:[PeopleResource class] withName:@"author"];
3131
});

Project/JSONAPI/PeopleResource.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ + (JSONAPIResourceDescriptor*)descriptor {
2323
[__descriptor setIdProperty:@"ID"];
2424

2525
[__descriptor addProperty:@"firstName" withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:@"first-name"]];
26-
[__descriptor addProperty:@"lastName" withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:@"last-name"]];
26+
[__descriptor addProperty:@"lastName" withJsonName:@"last-name"];
2727
[__descriptor addProperty:@"twitter"];
2828
});
2929

Project/JSONAPITests/JSONAPITests.m

+20-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#import "JSONAPIResourceDescriptor.h"
1313
#import "JSONAPIErrorResource.h"
1414
#import "JSONAPIResourceParser.h"
15+
#import "NSDateFormatter+JSONAPIDateFormatter.h"
1516

1617
#import "CommentResource.h"
1718
#import "PeopleResource.h"
@@ -65,10 +66,12 @@ - (void)testDataArticles {
6566
ArticleResource *article = jsonAPI.resource;
6667
XCTAssert([article isKindOfClass:[ArticleResource class]], @"Article should be a ArticleResource");
6768
XCTAssertEqualObjects(article.ID, @"1", @"Article id should be 1");
69+
XCTAssertTrue([article.selfLink isEqualToString:@"http://example.com/articles/1"], @"Article selfLink should be 'http://example.com/articles/1'");
6870
XCTAssertEqualObjects(article.title, @"JSON API paints my bikeshed!", @"Article title should be 'JSON API paints my bikeshed!'");
6971

70-
NSArray *dateStrings = @[@"2015-09-01T12:15:00Z",@"2015-08-01T06:15:00Z"];
71-
XCTAssertEqualObjects(article.versions, dateStrings, @"Article versions should contain an array of date strings");
72+
NSArray *dates = @[[[NSDateFormatter RFC3339DateFormatter] dateFromString:@"2015-09-01T12:15:00.000Z"],
73+
[[NSDateFormatter RFC3339DateFormatter] dateFromString:@"2015-08-01T06:15:00.000Z"]];
74+
XCTAssertEqualObjects(article.versions, dates, @"Article versions should contain an array of date objects");
7275
}
7376

7477
- (void)testIncludedPeopleAndComments {
@@ -181,13 +184,21 @@ - (void)testSerializeComplex {
181184
}
182185

183186
- (void)testCreate {
184-
PeopleResource *newAuthor = [[PeopleResource alloc] init];
185-
186-
newAuthor.firstName = @"Karl";
187-
newAuthor.lastName = @"Armstrong";
188-
189-
JSONAPI *jsonAPI = [JSONAPI jsonAPIWithResource:newAuthor];
190-
XCTAssertEqualObjects([jsonAPI dictionary][@"data"][@"type"], @"people", @"Did not create person!");
187+
NSDictionary *json = [self mainExampleJSON];
188+
JSONAPI *jsonAPI = [JSONAPI jsonAPIWithDictionary:json];
189+
190+
ArticleResource *article = jsonAPI.resource;
191+
192+
jsonAPI = [JSONAPI jsonAPIWithResource:article];
193+
NSDictionary *dictionary = [jsonAPI dictionary];
194+
XCTAssertEqualObjects(dictionary[@"data"][@"type"], @"articles", @"Did not create article!");
195+
XCTAssertEqualObjects(dictionary[@"data"][@"attributes"][@"title"], @"JSON API paints my bikeshed!", @"Did not parse title!");
196+
XCTAssertEqual([dictionary[@"data"][@"relationships"][@"comments"][@"data"] count], 2, @"Did not parse relationships!");
197+
XCTAssertEqual([dictionary[@"included"] count], 3, @"Did not parse included resources!");
198+
XCTAssertEqualObjects(dictionary[@"included"][0][@"type"], @"people", @"Did not parse included people object!");
199+
XCTAssertEqualObjects(dictionary[@"included"][0][@"id"], @"9", @"Did not parse ID!");
200+
XCTAssertEqualObjects(dictionary[@"included"][1][@"type"], @"comments", @"Did not parse included comments object!");
201+
XCTAssertEqualObjects(dictionary[@"included"][1][@"relationships"][@"author"][@"data"][@"type"], @"people", @"Did not parse included comments author!");
191202
}
192203

193204
#pragma mark - Generic relationships tests

Project/JSONAPITests/main_example.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
"attributes": {
1414
"title": "JSON API paints my bikeshed!",
1515
"versions": [
16-
"2015-09-01T12:15:00Z",
17-
"2015-08-01T06:15:00Z"
16+
"2015-09-01T12:15:00.000Z",
17+
"2015-08-01T06:15:00.000Z"
1818
]
1919
},
2020
"relationships": {

0 commit comments

Comments
 (0)