Skip to content

Commit 4b858e4

Browse files
author
Josh Holtz
committed
Merge pull request #9 from joshdholtz/1.0.0-rc1
1.0.0 rc1 - Updates to 1.0.0-rc3 of JSON API spec
2 parents c2c9290 + a9f8a34 commit 4b858e4

22 files changed

+418
-717
lines changed

Classes/JSONAPI.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,28 @@
1010

1111
#import "JSONAPIResource.h"
1212
#import "JSONAPIResourceFormatter.h"
13-
#import "JSONAPIResourceLinker.h"
1413
#import "JSONAPIResourceModeler.h"
14+
#import "JSONAPIErrorResource.h"
1515

1616
@interface JSONAPI : NSObject
1717

18-
@property (nonatomic, strong) NSDictionary *meta;
19-
@property (nonatomic, strong) NSDictionary *linked;
20-
@property (nonatomic, strong) NSError *error;
18+
@property (nonatomic, strong, readonly) NSDictionary *meta;
19+
@property (nonatomic, strong, readonly) id data;
20+
@property (nonatomic, strong, readonly) NSArray *errors;
2121

22-
+ (id)JSONAPIWithString:(NSString*)string;
23-
+ (id)JSONAPIWithDictionary:(NSDictionary*)dictionary;
22+
@property (readonly) id resource;
23+
@property (nonatomic, strong, readonly) NSArray *resources;
24+
@property (nonatomic, strong, readonly) NSDictionary *includedResources;
2425

25-
- (id)initWithString:(NSString*)string;
26-
- (id)initWithDictionary:(NSDictionary*)dictionary;
26+
@property (nonatomic, strong, readonly) NSError *internalError;
2727

28-
- (id)objectForKey:(NSString*)key;
29-
- (id)resourceForKey:(NSString*)key;
30-
- (NSArray*)resourcesForKey:(NSString*)key;
28+
// Initializers
29+
+ (instancetype)jsonAPIWithDictionary:(NSDictionary *)dictionary;
30+
+ (instancetype)jsonAPIWithString:(NSString *)string;
31+
- (instancetype)initWithDictionary:(NSDictionary*)dictionary;
32+
- (instancetype)initWithString:(NSString*)string;
33+
34+
- (id)includedResource:(id)ID withType:(NSString*)type;
35+
- (BOOL)hasErrors;
3136

3237
@end

Classes/JSONAPI.m

Lines changed: 79 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#import "JSONAPI.h"
1010

11+
#import "JSONAPIErrorResource.h"
12+
1113
@interface JSONAPI()
1214

1315
@property (nonatomic, strong) NSDictionary *dictionary;
@@ -16,28 +18,30 @@ @interface JSONAPI()
1618

1719
@implementation JSONAPI
1820

19-
#pragma mark - Init
21+
#pragma mark - Class
2022

21-
+ (id)JSONAPIWithString:(NSString*)string {
22-
return [[JSONAPI alloc] initWithString:string];
23+
+ (instancetype)jsonAPIWithDictionary:(NSDictionary *)dictionary {
24+
return [[JSONAPI alloc] initWithDictionary:dictionary];
2325
}
2426

25-
+ (id)JSONAPIWithDictionary:(NSDictionary*)dictionary {
26-
return [[JSONAPI alloc] initWithDictionary:dictionary];
27+
+ (instancetype)jsonAPIWithString:(NSString *)string {
28+
return [[JSONAPI alloc] initWithString:string];
2729
}
2830

29-
- (id)initWithString:(NSString*)string {
31+
#pragma mark - Instance
32+
33+
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
3034
self = [super init];
3135
if (self) {
32-
[self inflateWithString:string];
36+
[self inflateWithDictionary:dictionary];
3337
}
3438
return self;
3539
}
3640

37-
- (id)initWithDictionary:(NSDictionary*)dictionary {
41+
- (instancetype)initWithString:(NSString*)string {
3842
self = [super init];
3943
if (self) {
40-
[self inflateWithDictionary:dictionary];
44+
[self inflateWithString:string];
4145
}
4246
return self;
4347
}
@@ -48,102 +52,100 @@ - (void)inflateWithString:(NSString*)string {
4852
if ([json isKindOfClass:[NSDictionary class]] == YES) {
4953
[self inflateWithDictionary:json];
5054
} else {
51-
_error = [NSError errorWithDomain:@"Could not parse JSON" code:0 userInfo:nil];
55+
_internalError = [NSError errorWithDomain:@"Could not parse JSON" code:0 userInfo:nil];
5256
}
5357
}
5458

5559
#pragma mark - Resources
5660

57-
- (id)objectForKey:(NSString*)key {
58-
return [_dictionary objectForKey:key];
61+
- (id)resource {
62+
return _resources.firstObject;
5963
}
6064

61-
- (id)resourceForKey:(NSString*)key {
62-
if ([key isEqualToString:@"meta"] == YES || [key isEqualToString:@"linked"] == YES) {
63-
return nil;
64-
}
65-
66-
NSDictionary *rawResource = [_dictionary objectForKey:key];
67-
JSONAPIResource *resource = nil;
68-
if ([rawResource isKindOfClass:[NSDictionary class]] == YES) {
69-
Class c = [JSONAPIResourceModeler resourceForLinkedType:[JSONAPIResourceLinker linkedType:key]];
70-
resource = [JSONAPIResource jsonAPIResource:rawResource withLinked:self.linked withClass:c];
71-
}
72-
73-
// Fall back to first element in array
74-
if (resource == nil) {
75-
id resources = [self resourcesForKey:key];
76-
if ([resources isKindOfClass:[NSArray class]] == YES) {
77-
return [resources firstObject];
78-
}
79-
}
80-
81-
return resource;
82-
65+
- (id)includedResource:(id)ID withType:(NSString *)type {
66+
if (ID == nil) return nil;
67+
if (type == nil) return nil;
68+
return _includedResources[type][ID];
8369
}
8470

85-
- (NSArray*)resourcesForKey:(NSString*)key {
86-
if ([key isEqualToString:@"meta"] == YES || [key isEqualToString:@"linked"] == YES) {
87-
return nil;
88-
}
89-
90-
NSArray *rawResources = [_dictionary objectForKey:key];
91-
NSArray *resources = nil;
92-
if ([rawResources isKindOfClass:[NSArray class]] == YES) {
93-
Class c = [JSONAPIResourceModeler resourceForLinkedType:[JSONAPIResourceLinker linkedType:key]];
94-
resources = [JSONAPIResource jsonAPIResources:rawResources withLinked:self.linked withClass:c];
95-
}
96-
97-
return resources;
71+
- (BOOL)hasErrors {
72+
return _errors.count > 0;
9873
}
9974

10075
#pragma mark - Private
10176

10277
- (void)inflateWithDictionary:(NSDictionary*)dictionary {
103-
// Sets dictionary
78+
79+
// Sets internal dictionary
10480
_dictionary = dictionary;
10581

10682
// Sets meta
107-
_meta = [dictionary objectForKey:@"meta"];
83+
_meta = dictionary[@"meta"];
10884
if ([_meta isKindOfClass:[NSDictionary class]] == NO) {
10985
_meta = nil;
11086
}
11187

112-
// Sets linked
113-
NSMutableDictionary *creatingLinked = [NSMutableDictionary dictionary];
114-
NSDictionary *rawLinked = [dictionary objectForKey:@"linked"];
115-
if ([rawLinked isKindOfClass:[NSDictionary class]] == YES) {
88+
// Parse resources
89+
_data = _dictionary[@"data"];
90+
91+
NSMutableArray *resources = @[].mutableCopy;
92+
if ([_data isKindOfClass:[NSArray class]] == YES) {
93+
94+
NSArray *dataArray = (NSArray*) _data;
95+
for (NSDictionary *data in dataArray) {
96+
id resource = [self inflateResourceData:data];
97+
if (resource) [resources addObject:resource];
98+
}
11699

117-
NSMutableArray *linkedToLinkWithLinked = [NSMutableArray array];
100+
} else if ([_data isKindOfClass:[NSDictionary class]] == YES) {
101+
id resource = [self inflateResourceData:_data];
102+
if (resource) [resources addObject:resource];
103+
}
104+
_resources = resources;
105+
106+
// Parses included resources
107+
NSArray *included = _dictionary[@"included"];
108+
NSMutableDictionary *includedResources = @{}.mutableCopy;
109+
for (NSDictionary *data in included) {
118110

119-
// Loops through linked arrays
120-
for (NSString *key in rawLinked.allKeys) {
121-
NSArray *value = [rawLinked objectForKey:key];
122-
123-
if ([value isKindOfClass:[NSArray class]] == YES) {
124-
NSMutableDictionary *resources = [NSMutableDictionary dictionary];
125-
for (NSDictionary *resourceDictionary in value) {
126-
Class c = [JSONAPIResourceModeler resourceForLinkedType:[JSONAPIResourceLinker linkedType:key]];
127-
JSONAPIResource *resource = [JSONAPIResource jsonAPIResource:resourceDictionary withLinked:nil withClass:c];
128-
if (resource.ID != nil) {
129-
[resources setObject:resource forKey:resource.ID];
130-
[linkedToLinkWithLinked addObject:resource];
131-
}
132-
}
133-
[creatingLinked setObject:resources forKey:key];
134-
135-
}
111+
JSONAPIResource *resource = [self inflateResourceData:data];
112+
if (resource) {
113+
114+
NSMutableDictionary *typeDict = includedResources[resource.type] ?: @{}.mutableCopy;
115+
typeDict[resource.ID] = resource;
136116

117+
includedResources[resource.type] = typeDict;
137118
}
138-
139-
// Linked the linked
140-
for (JSONAPIResource *resource in linkedToLinkWithLinked) {
141-
[resource linkLinks:creatingLinked];
119+
}
120+
_includedResources = includedResources;
121+
122+
// Link included with included
123+
// TODO: Need to look into / stop circular references
124+
for (NSDictionary *typeIncluded in _includedResources.allValues) {
125+
for (JSONAPIResource *resource in typeIncluded.allValues) {
126+
[resource linkWithIncluded:self];
142127
}
143-
144128
}
145129

146-
_linked = creatingLinked;
130+
// Link data with included
131+
for (JSONAPIResource *resource in _resources) {
132+
[resource linkWithIncluded:self];
133+
}
134+
135+
// Parse errors
136+
NSMutableArray *errors = @[].mutableCopy;
137+
NSLog(@"ERROS - %@", _dictionary[@"errors"]);
138+
for (NSDictionary *data in _dictionary[@"errors"]) {
139+
140+
JSONAPIErrorResource *resource = [[JSONAPIErrorResource alloc] initWithDictionary:data];
141+
NSLog(@"Error resource - %@", resource);
142+
if (resource) [errors addObject:resource];
143+
}
144+
_errors = errors;
145+
}
146+
147+
- (id)inflateResourceData:(NSDictionary*)data {
148+
return [JSONAPIResource jsonAPIResource:data];
147149
}
148150

149151
@end

Classes/JSONAPIErrorResource.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// JSONAPIErrorResource.h
3+
// JSONAPI
4+
//
5+
// Created by Josh Holtz on 3/17/15.
6+
// Copyright (c) 2015 Josh Holtz. All rights reserved.
7+
//
8+
9+
#import "JSONAPIResource.h"
10+
11+
@interface JSONAPIErrorResource : JSONAPIResource
12+
13+
@property (nonatomic, strong) NSString *status;
14+
@property (nonatomic, strong) NSString *code;
15+
@property (nonatomic, strong) NSString *title;
16+
@property (nonatomic, strong) NSString *detail;
17+
@property (nonatomic, strong) NSArray *links;
18+
@property (nonatomic, strong) NSArray *paths;
19+
20+
@end

Classes/JSONAPIErrorResource.m

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// JSONAPIErrorResource.m
3+
// JSONAPI
4+
//
5+
// Created by Josh Holtz on 3/17/15.
6+
// Copyright (c) 2015 Josh Holtz. All rights reserved.
7+
//
8+
9+
#import "JSONAPIErrorResource.h"
10+
11+
@implementation JSONAPIErrorResource
12+
13+
- (NSDictionary *)mapKeysToProperties {
14+
return @{
15+
@"status" : @"status",
16+
@"code" : @"code",
17+
@"title" : @"title",
18+
@"detail" : @"detail",
19+
@"paths" : @"paths",
20+
};
21+
}
22+
23+
@end

Classes/JSONAPIResource.h

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,20 @@
88

99
#import <Foundation/Foundation.h>
1010

11+
@class JSONAPI;
12+
1113
@interface JSONAPIResource : NSObject<NSCopying, NSCoding>
1214

1315
@property (nonatomic, strong) id ID;
14-
@property (nonatomic, strong) NSString *href;
15-
@property (nonatomic, strong) NSDictionary *links;
16-
17-
+ (NSArray*)jsonAPIResources:(NSArray*)array withLinked:(NSDictionary*)linked;
18-
+ (NSArray*)jsonAPIResources:(NSArray*)array withLinked:(NSDictionary*)linked withClass:(Class)resourceObjectClass;
19-
20-
+ (id)jsonAPIResource:(NSDictionary*)dictionary withLinked:(NSDictionary*)linked;
21-
+ (id)jsonAPIResource:(NSDictionary*)dictionary withLinked:(NSDictionary*)linked withClass:(Class)resourceObjectClass;
22-
23-
- (id)initWithDictionary:(NSDictionary*)dict withLinked:(NSDictionary*)linked;
24-
- (void)setWithDictionary:(NSDictionary*)dict;
16+
@property (nonatomic, strong) NSString *type;
17+
@property (nonatomic, strong) id links;
2518

26-
- (id)objectForKey:(NSString*)key;
27-
- (id)linkedResourceForKey:(NSString*)key;
19+
+ (id)jsonAPIResource:(NSDictionary*)dictionary;
20+
+ (NSArray*)jsonAPIResources:(NSArray*)array;
2821

29-
- (void)linkLinks:(NSDictionary*)linked;
22+
- (id)initWithDictionary:(NSDictionary*)dict;
3023

3124
- (NSDictionary *)mapKeysToProperties;
25+
- (void)linkWithIncluded:(JSONAPI*)jsonAPI;
3226

3327
@end

0 commit comments

Comments
 (0)