TestsTested | ✓ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Dec 2014 |
Maintained by Todd Grooms, Aaron London.
Depends on: | |
AFNetworking | ~> 2.3.1 |
CoreDataMate | ~> 0.1 |
LPMJSONUtils | ~> 1.0.0 |
Mantle | ~> 1.5 |
LPMSirenKit
is a lightweight library for interacting with Hypermedia APIs that adhere to the Siren specification.
LPMSirenKit
sits on top of AFNetworking
and submits requests on behalf of the application. The library will parse the results and cache the entity, link, action, and field objects. The properties
for the entity objects are not cached at this level (the library only caches those things that are necessary for navigation).
$ git clone [email protected]:lonelyplanet/lpm-sirenkit-ios.git
$ cd lpm-sirenkit-ios/Example
$ pod install
LPMSirenKit.xcworkspace
$ open LPMSirenKit.xcworkspace
Now you can run the project from Xcode. Once the application launches, you will be presented with a screen that will request a URL for a server you wish to run the application against and the location of the manifest. In our definition, the manifest is simply the location of the initial SirenEntity. For most servers, you can leave this field blank as the initial SirenEntity is located at the root URL you specify.
You will create an LPMSirenSessionManager
with a base URL, a path to where the manifest for the API can be found, and an instance of NSURLSessionConfiguration
(the defaultSessionConfiguration
works really well). The manifest is simply the root of the API or, rather, where the API indicates what root level links and/or actions are available. Initialize your LPMSirenSessionManager
:
LPMSirenSessionManager *sirenSessionManager = [[LPMSirenSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://siren.api"]
manifestPath:manifestPath
sessionConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration];
You will then need to request the manifest:
[sirenSessionManager GETManifestWithParameters:nil completion:^(LPMSirenEntityModel *manifestEntity, NSError *error) {
// Check manifestEntity and error to determine if request was successful
}];
When you request the manifest, you are fetching the initial SirenEntity which is where you start traversing the API. This entity will most likely contain top-level SirenLinks and SirenActions for the API.
After successfully requesting the API's manifest, you are ready to rock. If you take one of the LPMSirenLinkModel
s that is connected to the manifest LPMSirenEntityModel
(since the manifest is just a LPMSirenEntityModel
, you can check the manifestEntityModel.sirenLinks
relationship for any LPMSirenLinkModel
s you wish to use), you can request links by using the LPMSirenLinkModel
:
[sirenSessionManager GETLink:sirenLinkModel withParameters:nil completion:^(LPMSirenEntityModel *sirenEntityModel, NSError *error) {
// Check sirenEntityModel and error to determine if request was successful
} error:&error];
Or by using the link's relationship(s) and the GUID of the entity that owns the link:
[sirenSessionManager GETLinkForRelationship:@"self" ofEntityWithGUID:@"guid" withParameters:nil completion:^(LPMSirenEntityModel *sirenEntityModel, NSError *error) {
// Check sirenEntityModel and error to determine if request was successful
} error:&error];
If the LPMSirenLinkModel
is not found for the request method that performs the lookup on LPMSirenKit
's local cache, GETLinkForRelationship:ofEntityWithGUID:withParameters:completion:error:
will return nil
instead of a valid NSURLSessionDataTask
and an error code of SirenKitError_ErrorCode_LinkNotFound
is given in the NSError
parameter.
You can submit actions by using the LPMSirenActionModel
with a dictionary of parameters:
[sirenSessionManager HTTPActionWithSirenAction:sirenActionModel withParameters:parameters completion:^(LPMSirenEntityModel *sirenEntityModel, NSError *error) {
// Check sirenEntityModel and error to determine if request was successful
} error:&error];
Or by using the action's name and the GUID of the entity that owns the action:
[sirenSessionManager HTTPActionWithName:@"action" onEntityWithGUID:@"guid" withParameters:parameters completion:^(LPMSirenEntityModel *sirenEntityModel, NSError *error) {
// Check sirenEntityModel and error to determine if request was successful
} error:&error];
If the LPMSirenActionModel
is not found for the request method that performs the lookup on LPMSirenKit
's local cache, HTTPActionWithName:onEntityWithGUID:withParameters:completion:error:
will return nil
instead of a valid NSURLSessionDataTask
and an error code of SirenKitError_ErrorCode_ActionNotFound
is given in the NSError
parameter.
LPMSirenKit
will attempt to map the parameters given for an action request to the fields associated with that action. Any keys in the parameters dictionary that do not have corresponding LPMSirenFieldModel
s for the specified LPMSirenActionModel
will be ignored in the request (matched by the name
property). If you try to set the value of a hidden field, this will be ignored in the request. LPMSirenKit
also attempts to match types. For example, if a field indicates that it is a number
or url
input type, LPMSirenKit
validates that the value given for these keys matches the same type (i.e. NSNumber
or NSURL
). If the type does not match, an error code of SirenKitError_ErrorCode_FieldTypeMismatch
is given in the NSError
parameter.
Are you interacting with an authenticated Siren API? Cool! We (at Lonely Planet) are as well. LPMSirenSessionManager
supports the use of a HTTP Authorization header. Simply set the authorizationHeaderValue
property and all subsequent requests will include the header:
sirenSessionManager.authorizationHeaderValue = @"Bearer some-hex-string";
Each entity requires a globally unique identifier. However, different APIs use different identifiers and, within the same API, different types/kinds of entities can use different identifiers. LPMSirenSessionStore
has a method that allows the client to specify where these GUIDs can be found for each kind of entity.
[LPMSirenSessionStore setGUIDMappingDictionary:@{
@"order": @"properties.orderNumber",
@"items, collection": @"href",
@"info, customer": @"properties.customerId"
}];
In the above scenario, the key should match the entity's class
. The value
will be the path for the identifier after the response is parsed into LPMSirenEntityModel
s, LPMSirenLinkModel
s, or LPMSirenActionModel
s.
If I would like to make a place/collection entity's GUID that entity's 'self' link, the mapping may look like this:
@"places, collection": @"sirenLinks[0].href" // First link is usually 'self'
Or
@"places, collection": @"sirenLinks[@rel~self].href" // A link whose rel property contains the 'self' identifier; This means rel could be "self" or "this, self" and it would be found
Or even
@"places, collection": @"sirenLinks[@rel=self].href" // A link whose rel property is equal to the 'self' identifier; This means rel has to be "self" to be found
LPMSirenKit
currently uses Core Data to cache the Siren related metadata when parsing responses from the server. This is used to help quickly recall what entities, links, and actions a server supports quickly before subsequent requests. LPMSirenKit
uses an embedded data store that you as a developer will not have to worry about or maintain. For more information about this data store, check out the LPMSirenKit.xcdatamodeld
, ManagedSirenEntity
, ManagedSirenLink
, ManagedSirenField
, and/or ManagedSirenAction
.
LPMSirenKit
depends on several other libraries: AFNetworking, CoreDataMate, LPMJSONUtils, and Mantle. These are included as dependencies in the .podspec and will be installed upon running pod install
after adding LPMSirenKit
to your Podfile.
LPMSirenKit
is available through CocoaPods. To install
it, simply add the following line to your Podfile:
pod 'LPMSirenKit'
Todd Grooms, [email protected]
LPMSirenKit
is available under the MIT license. See the LICENSE file for more info.