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