Alex Johnson
@nonsensery
Burning Down the Bike Shed
Agenda
A little history
A tour of the spec
Ember Data support
Should you use it?
A little history*
* Accuracy not guaranteed
JSON API 0.x
May 2013
Extracted from the JSON transport implicitly defined by Ember Data's REST adapter.
— jsonapi.org/about
"This is a fairly thorough rewrite of the spec."
JSON API 1.0 (rc1)
June 2014
— github.com/json-api/json-api/pull/234
JSON API 1.0
May 2015
"After two years … we're finally ready to declare the JSON API specification stable!"
— github.com/json-api/json-api/pull/727
JSON API 1.0+
The base specification will remain backwards compatible using a never remove, only add strategy.
— jsonapi.org/status
A tour of the format
It Has a Media Type
application/vnd.api+json
PATCH /posts/9 HTTP/1.1
Accept: application/vnd.api+json
Content-Type: application/vnd.api+json
…
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
…
It's JSON (duh!)
{
"data": {
"type": "posts",
"id": "7",
"attributes": {
…
},
"relationships": {
…
}
}
}
It Uses HTTP "Correctly"
Resources and Collections have unique URLs.
HTTP methods define the actions to take.
Action | Method | Response Status* |
---|---|---|
Fetch | GET | 200 OK |
Create | POST | 201 Created or 204 No Content |
Modify | PATCH | 200 OK or 204 No Content |
Destroy | DELETE | 204 No Content or 200 OK |
* These are just examples. Many other HTTP status codes are allowed, like 404 (Not Found) when fetching a resource that doesn't exist.
It Uses Hypermedia
Responses (can) include URLs for interacting with the resources and collections they contain.
"links": {
"self": "http://awesome.sauce/posts/",
"next": "http://awesome.sauce/posts?page[offset]=2",
"last": "http://awesome.sauce/posts?page[offset]=10"
}
"comments": {
"links": {
"self": "/posts/1/relationships/comments",
"related": "/posts/1/comments"
}
}
It's Metadata-Friendly
{
"meta": { "whateva": "you", "like": "brah" },
…
"data": {
"meta": { "here": "too", "dog": [] },
…
"relationships": {
"author": {
"type": "people",
"id": "9",
"meta": { "yup.": "#dealwithit" }
},
…
}
}
}
It's Designed for Failure
{
"errors": [{
"title": "Request Denied",
"detail": "Ah ah ah, you didn't say the magic word.",
"status": "403",
"code": "1124",
"id": "2d9f03d5-12c1-4476-ac5f-1544412e85c5",
"links": { "about": "http://youtu.be/RfiQYRn7fBg" },
"meta": { "here too?": true }
}, {
"title": "Invalid Parameter",
"status": "400",
"source": {
"parameter": "fields[posts]"
}
}]
}
It's Designed for Efficiency
/posts?include=author,comments,comments.author
/posts?fields[post]=title,date
Side-Loading:
/posts?sort=date&page[number]=2&filter[tags]=popular
Sparse Fieldsets:
Sorting, Filtering and Pagination:
It's all about Resources.
Articles
Comments
Tags
People
Companies
Products
Resources are identified by type
and id
.
{
"type": "posts",
"id": "7"
}
An object with only type
and id
is called a Resource Identifier Object.
We'll see more of them soon…
Identification
Resources can have attributes and relationships.
{
"type": "posts",
"id": "7",
"attributes": {
"title": "JSON API paints my bikeshed!",
"published": {
"year": "2015",
"month": "06",
"day": "30"
},
"cover-photos": [
"http://giphy.com/embed/oOAuubU8LEI0w",
"http://giphy.com/embed/IhGwYlCgBOww0"
]
}
}
Attributes!
Primitives
Objects
Arrays
{
"type": "posts",
"id": "7",
"relationships": {
"author": {
"data": { "type": "people", "id": "9" }
},
"comments": {
"data": [
{ "type": "comments", "id": "5" },
{ "type": "comments", "id": "12" }
]
}
}
}
Relationships!
To-One
To-Many
… Hey, look — Resource Identifier Objects!
{
"type": "posts",
"id": "7",
"relationships": {
"author": {
"links": { "related": "/posts/7/author" }
},
"comments": {
"links": { "related": "/posts/7/comments" }
}
}
}
"Asynchronous" Relationships
(via Hypermedia URLs)
Update to-one relationships with PATCH.
Update to-many relationships with PATCH, POST and DELETE.
It's Indifferent to Things Like…
/some-fish-swim-left
{ "type": "sharks", … }
URL Structure:
"first-name": "Wehadababy"
"last-name": "Itsaboy"
"first_name": "Wehadababy"
"last_name": "Itsaboy"
{ "type": "shark", … }
/some/fish/swim/right
Inflection Choices:
Multi-word Format:
vs.
vs.
vs.
Ember Data Support
Why?
Getting [our models] into the browser requires every developer write custom, imperative code. It's a colossal waste of human time and energy.
Phase 1:
A Working Adapter
After Some Discussion…
I believe JSONAPI dropped the recom-
mendation that these keys be dasherized?
the url should be /posts here. They are always pluralized.
This is currently intentional as JSON-API does not state anything about URLs being singular/plural.
And After Forming Some Opinions…
types are serialized to, and expected to be plural dasherized when received from the server
member names are serialized to, and expected to be dasherized when received from the server
URLs are … plural dasherized by default
Merged on June 15th
Phase 2:
JSON API as Ember Data's "native" language
What Does "Native" Mean?
API changes are opt-in today, default in Ember 2.0
Internal data stored as JSON API
Serializers convert to/from JSON API
Relationships are asynchronous
Ember Data 1.13 & 2.0-beta
Should You Use It?
It Depends…
Is your API your special sauce?
Are you OK using a fairly young spec?
What clients do you need to support?
Ember Data, Backbone, iOS and Ruby client libraries exist
Are you OK using fairly young libraries?
They're probably more mature than your code…
Are you willing to conform?
It's not about bike-shedding. It's about interoperability!
JSON API
By nonsensery
JSON API
A presentation on JSON API for the June 2015 Portland Ember.js meetup.
- 1,250