/jsonapi-ios

A library for loading data from a JSON API datasource.

Primary LanguageObjective-CMIT LicenseMIT

JSONAPI - iOS

Build Status Join the chat at https://gitter.im/joshdholtz/jsonapi-ios

A library for loading data from a JSON API datasource. Parses JSON API data into models with support for linking of properties and other resources.

Quick Usage

NSDictionary *json = [self responseFromAPIRequest];
JSONAPI *jsonAPI = [JSONAPI jsonAPIWithDictionary:json];

ArticleResource *article = jsonAPI.resource;
NSLog(@"Title: %@", article.title);

For some full examples on how to use everything, please see the tests - https://github.com/joshdholtz/jsonapi-ios/blob/master/Project/JSONAPITests/JSONAPITests.m

Updates

Version Changes
1.0.7 Added meta and setMeta to JSONAPIResource and JSONAPIResourceBase (joshdholtz#43).
1.0.6 Improved resource parsing and added parsing of selfLinks (joshdholtz#35). Thanks to [ artcom](https://github.com/ artcom) for helping! Also removed the need to define setIdProperty and setSelfLinkProperty in every resource (automatically mapped in the init of JSONAPIResourceDescriptor)
1.0.5 Fix 1-to-many relationships serialization according to JSON API v1.0 (joshdholtz#34). Thanks to RafaelKayumov for helping!
1.0.4 Add support for empty to-one relationship according to JSON API v1.0 (joshdholtz#33). Thanks to RafaelKayumov for helping!
1.0.3 Add ability to map different types of objects (joshdholtz#32). Thanks to ealeksandrov for helping!
1.0.2 Just some bug fixes. Thanks to christianklotz for helping again!
1.0.1 Now safely checks for NSNull in the parsed JSON. Thanks to christianklotz for that fix!
1.0.0 We did it team! We are at the JSON API 1.0 final spec. Resources now use JSONAPIResourceDescriptor for more explicit definitions. HUGE thanks to jkarmstr for doing all the dirty work. Also thanks to edopelawi , BenjaminDigeon, and christianklotz for some bug fixes!
1.0.0-rc1 Rewrote core of JSONAPI and JSONAPIResource and all unit tests to be up to spec with JSON API spec 1.0.0-rc3. Removed JSONAPIResourceLinker. Added JSONAPIErrorResource
0.2.0 Added NSCopying and NSCoded to JSONAPIResource; Added JSONAPIResourceFormatter to format values before getting mapped - more info
0.1.2 JSONAPIResource IDs can either be numbers or strings (thanks danylhebreux); JSONAPIResource subclass can have mappings defined to set JSON values into properties automatically - more info
0.1.1 Fixed linked resources with links so they actually link to other linked resources
0.1.0 Initial release

Features

  • Allows resource types to be created into subclasses of JSONAPIResource
  • Set mapping for JSONAPIResource subclass to set JSON values and relationships into properties

Installation

Drop-in Classes

Clone the repository and drop in the .h and .m files from the "Classes" directory into your project.

CocoaPods

JSONAPI is available through CocoaPods, to install it simply add the following line to your Podfile:

pod 'JSONAPI', '~> 1.0.7'

Classes/protocols

For some full examples on how to use everything, please see the tests - https://github.com/joshdholtz/jsonapi-ios/blob/master/Project/JSONAPITests/JSONAPITests.m

JSONAPI

JSONAPI parses and validates a JSON API document into a usable object. This object holds the response as an NSDictionary but provides methods to accomdate the JSON API format such as meta, errors, linked, resources, and includedResources.

JSONAPIResource

Protocol of an object that is available for JSON API serialization. When developing model classes for use with JSON-API, it is suggested that classes be derived from JSONAPIResourceBase, but that is not required. An existing model class can be adapted for JSON-API by implementing this protocol.

JSONAPIResourceBase

JSONAPIResourceBase is an object (that gets subclassed) that holds data for each resource in a JSON API document. This objects holds the "id" as ID and link for self as selfLink as well as attributes and relationships defined by descriptors (see below)

JSONAPIResourceDescriptor

+ (JSONAPIResourceDescriptor*)descriptor should be overwritten to define descriptors for mapping of JSON keys and relationships into properties of a subclassed JSONAPIResource.

Full Example

ViewController.m

NSDictionary *json = [self responseFromAPIRequest];
JSONAPI *jsonAPI = [JSONAPI jsonAPIWithDictionary:json];

ArticleResource *article = jsonAPI.resource;
NSLog(@"Title: %@", article.title);
NSLog(@"Author: %@ %@", article.author.firstName, article.author.lastName);
NSLog(@"Comment Count: %ld", article.comments.count);

ArticleResource.h

@interface ArticleResource : JSONAPIResourceBase

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) PeopleResource *author;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSArray *comments;

@end

ArticleResource.m

@implementation ArticleResource

static JSONAPIResourceDescriptor *__descriptor = nil;

+ (JSONAPIResourceDescriptor*)descriptor {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __descriptor = [[JSONAPIResourceDescriptor alloc] initWithClass:[self class] forLinkedType:@"articles"];

        [__descriptor addProperty:@"title"];
        [__descriptor addProperty:@"date"
                 withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:@"date" withFormat:[NSDateFormatter RFC3339DateFormatter]]];

        [__descriptor hasOne:[PeopleResource class] withName:@"author"];
        [__descriptor hasMany:[CommentResource class] withName:@"comments"];
    });

    return __descriptor;
}

@end

PeopleResource.h

@interface PeopleResource : JSONAPIResourceBase

@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSString *twitter;

@end

PeopleResource.m

@implementation PeopleResource

static JSONAPIResourceDescriptor *__descriptor = nil;

+ (JSONAPIResourceDescriptor*)descriptor {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __descriptor = [[JSONAPIResourceDescriptor alloc] initWithClass:[self class] forLinkedType:@"people"];

        [__descriptor addProperty:@"firstName" withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:@"first-name"]];
        [__descriptor addProperty:@"lastName" withJsonName:@"last-name"];
        [__descriptor addProperty:@"twitter"];
    });

    return __descriptor;
}

@end

CommentResource.h

@interface CommentResource : JSONAPIResourceBase

@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) PeopleResource *author;

@end

CommentResource.m

@implementation CommentResource

static JSONAPIResourceDescriptor *__descriptor = nil;

+ (JSONAPIResourceDescriptor*)descriptor {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __descriptor = [[JSONAPIResourceDescriptor alloc] initWithClass:[self class] forLinkedType:@"comments"];

        [__descriptor addProperty:@"text" withJsonName:@"body"];

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

    return __descriptor;
}

@end

Advanced

How to do custom "sub-resources" mappings

Sometimes you may have parts of a resource that need to get mapped to something more specific than just an NSDictionary. Below is an example on how to map an NSDictionary to non-JSONAPIResource models.

We are essentially creating a property descriptor that maps to a private property on the resource. We then override that properties setter and do our custom mapping there.

Resource part of JSON API Response

"attributes":{
  "title": "Something something blah blah blah"
  "image": {
    "large": "http://someimageurl.com/large",
    "medium": "http://someimageurl.com/medium",
    "small": "http://someimageurl.com/small"
  }
}

ArticleResource.h

@interface ArticleResource : JSONAPIResourceBase

@property (nonatomic, strong) NSString *title;

// The properties we are pulling out of a a "images" dictionary
@property (nonatomic, storng) NSString *largeImageUrl;
@property (nonatomic, storng) NSString *mediumImageUrl;
@property (nonatomic, storng) NSString *smallImageUrl;

@end

ArticleResource.m

@interface ArticleResource()

// Private variable used to store raw NSDictionary
// We will override the setter and set our custom properties there
@property (nonatomic, strong) NSDictionary *rawImage;

@end

@implementation ArticleResource

static JSONAPIResourceDescriptor *__descriptor = nil;

+ (JSONAPIResourceDescriptor*)descriptor {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __descriptor = [[JSONAPIResourceDescriptor alloc] initWithClass:[self class] forLinkedType:@"articles"];

        [__descriptor addProperty:@"title"];
        [__descriptor addProperty:@"rawImage" withDescription:[[JSONAPIPropertyDescriptor alloc] initWithJsonName:@"image"]];

    });

    return __descriptor;
}

- (void)setRawImage:(NSDictionary*)rawImage {
  _rawImage = rawImage;

  // Pulling the large, medium, and small urls out when
  // this property gets set by the JSON API parser
  _largeImageUrl = _rawImage[@"large"];
  _mediumImageUrl = _rawImage[@"medium"];
  _smallImageUrl = _rawImage[@"small"];
}

@end

Author

Josh Holtz, me@joshholtz.com, @joshdholtz

License

JSONAPI is available under the MIT license. See the LICENSE file for more info.