SkillAgentSearch skills...

Spine

A Swift library for working with JSON:API APIs. It supports mapping to custom model classes, fetching, advanced querying, linking and persisting.

Install / Use

/learn @wvteijlingen/Spine
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Build Status Join the chat at https://gitter.im/wvteijlingen/Spine

I'm not maintaining this library anymore. The community is continuing development of Spine at jsonapi-ios/Spine. Feel free to use that fork, and submit pull-requests or open issues there.

The project that used this was shelved and I'm too busy with other work, so I cannot afford to spend time on this anymore. Feel free to fork this if you want, but don't expect me to maintain or help with issues for the foreseeable future. ❤️

Spine

Spine is a Swift library for working with APIs that adhere to the jsonapi.org standard. It supports mapping to custom model classes, fetching, advanced querying, linking and persisting.

Stability

This library was born out of a hobby project. Some things are still lacking, one of which is test coverage. Beware of this when using Spine in a production app!

Table of Contents

Supported features

| Feature | Supported | Note | | ------------------------------ | --------- | ----------------------------------------------- | | Fetching resources | Yes | | | Creating resources | Yes | | | Updating resources | Yes | | | Deleting resources | Yes | | | Top level metadata | Yes | | | Top level errors | Yes | | | Top level links | Yes | | | Top level JSON API Object | Yes | | | Client generated ID's | Yes | | | Resource metadata | Yes | | | Custom resource links | No | | | Relationships | Yes | | | Inclusion of related resources | Yes | | | Sparse fieldsets | Partially | Fetching only, all fields will be saved | | Sorting | Yes | | | Filtering | Yes | Supports custom filter strategies | | Pagination | Yes | Offset, cursor and custom pagination strategies | | Bulk extension | No | | | JSON Patch extension | No | |

Installation

Carthage

Add github "wvteijlingen/Spine" "master" to your Cartfile. See the Carthage documentation for instructions on how to integrate with your project using Xcode.

Cocoapods

Add pod 'Spine', :git => 'https://github.com/wvteijlingen/Spine.git' to your Podfile. The spec is not yet registered with the Cocoapods repository, because the library is still in flux.

Configuration

Defining resource types

Every resource is mapped to a class that inherits from Resource. A subclass should override the variables resourceType and fields. The resourceType should contain the type of resource in plural form. The fields array should contain an array of fields that must be persisted. Fields that are not in this array are ignored.

Each class must be registered using the Spine.registerResource method.

Defining resource fields

You need to specify the fields that must be persisted using an array of Fields. These fields are used when turning JSON into resources instances and vice versa. The name of each field corresponds to a variable on your resource class. This variable must be specified as optional.

Field name formatters

By default, the key in the JSON will be the same as your field name or serialized field name. You can specify a different name by using serializeAs(name: String). The name or custom serialized name will be mapped to a JSON key using a KeyFormatter. You can configure the key formatter using the keyFormatter variable on a Spine instance.

Spine comes with three key formatters: AsIsKeyFormatter, DasherizedKeyFormatter, UnderscoredKeyFormatter.

// Formats a field name 'myField' to key 'MYFIELD'.
public struct AllCapsKeyFormatter: KeyFormatter {
	public func format(field: Field) -> String {
		return field.serializedName.uppercaseString
	}
}

spine.keyFormatter = AllCapsKeyFormatter()

Built in attribute types

Attribute

An attribute is a regular attribute that can be serialized by NSJSONSerialization. E.g. a String or NSNumber.

URLAttribute

An url attribute corresponds to an NSURL variable. These are represented by strings in the JSON document. You can instantiate it with a baseURL, in which case Spine will expand relative URLs from the JSON relative to the given baseURL. Absolute URLs will be left as is.

DateAttribute

A date attribute corresponds to an NSDate variable. By default, these are represented by ISO 8601 strings in the JSON document. You can instantiate it with a custom format, in which case that format will be used when serializing and deserializing that particular attribute.

ToOneRelationship

A to-one relationship corresponds to another resource. You must instantiate it with the type of the linked resource.

ToManyRelationship

A to-many relationship corresponds to a collection of other resources. You must instantiate it with the type of the linked resources. If the linked types are not homogenous, they must share a common ancestor as the linked type. To many relationships are mapped to LinkedResourceCollection objects.

Custom attribute types

Custom attribute types can be created by subclassing Attribute. A custom attribute type must have a registered transformer that handles serialization and deserialization.

Transformers are registered using the registerTransformer method. A transformer is a class or struct that implements the Transformer protocol.

public class RomanNumeralAttribute: Attribute { }

struct RomanNumeralValueFormatter: ValueFormatter {
	func unformat(value: String, attribute: RomanNumeralAttribute) -> AnyObject {
		let integerRepresentation: NSNumber = // Magic...
		return integerRepresentation
	}

	func format(value: NSNumber, attribute: RomanNumeralAttribute) -> AnyObject {
		let romanRepresentation: String = // Magic...
		return romanRepresentation
	}
}
spine.registerValueFormatter(RomanNumeralValueFormatter())

Example resource class

// Resource class
class Post: Resource {
	var title: String?
	var body: String?
	var creationDate: NSDate?
	var author: User?
	var comments: LinkedResourceCollection?

	override class var resourceType: ResourceType {
		return "posts"
	}

	override class var fields: [Field] {
		return fieldsFromDictionary([
			"title": Attribute(),
			"body": Attribute().serializeAs("content"),
			"creationDate": DateAttribute(),
			"author": ToOneRelationship(User),
			"comments": ToManyRelationship(Comment)
		])
	}
}

spine.registerResource(Post)

Usage

Fetching resources

Resources can be fetched using find methods:

// Fetch posts with ID 1 and 2
spine.find(["1", "2"], ofType: Post).onSuccess { resources, meta, jsonapi in
  println("Fetched resource collection: \(resources)")
}.onFailure { error in
  println("Fetching failed: \(error)")
}

spine.findAll(Post) // Fetch all posts
spine.findOne("1", ofType: Post)  // Fetch a single posts with ID 1

Alternatively, you can use a Query to perform a more advanced find:

var query = Query(resourceType: Post)
query.include("author", "comments", "comments.author") // Sideload relationships
query.whereProperty("upvotes", equalTo: 8) // Only with 8 upvotes
query.addAscendingOrder("creationDate") // Sort on creation date

spine.find(query).onSuccess { resources, meta, jsonapi in
  println("Fetched resource collection: \(resources)")
}.onFailure { error in
  println("Fetching failed: \(error)")
}

All fetch methods return a Future with onSuccess and onFailure callbacks.

Saving resources

spine.save(post).onSuccess { _ in
    println("Saving success")
}.onFailure { error in
    println("Saving failed: \(error)")
}

Extra care MUST be taken regarding related resources. Saving does not automatically save any related resources. You must explicitly save these yourself beforehand. If you added a new create resource to a pare

View on GitHub
GitHub Stars263
CategoryCustomer
Updated11d ago
Forks108

Languages

Swift

Security Score

100/100

Audited on Mar 30, 2026

No findings