Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JSON-API – The ultimate anti-bikeshedding weapon

JSON-API – The ultimate anti-bikeshedding weapon

APIs are everywhere: many return JSON and are RESTful or even provide hypermedia controls, but chances are they do not adhere to any standard. Essentially they all speak a different language that has to be learned for each specific provider. Wouldn’t it be great if there was a sane specification that lets you standardize your API? Something around which the community can build tools so you don’t have to reinvent the wheel over and over again? In this talk I will introduce the JSON-API specification and explain how it can benefit you on your next API project.

Henning Glatter-Götz

February 02, 2016
Tweet

More Decks by Henning Glatter-Götz

Other Decks in Programming

Transcript

  1. "EACH TIME YOU WANT TO INTERACT WITH A NEW API

    YOU HAVE TO REWRITE A BRAND NEW CLIENT THAT SPEAKS ITS PARTICULAR FLAVOR OF WHATEVER THING IT IS THAT YOU ARE BUILDING" Steve Klabnik
  2. COVERED BY JSON-API SPEC Content Negotiation Document Structure Fetching Data

    Creating, Updating and Deleting Resources Query Parameters Errors HTTP status codes
  3. ARTICLES MODEL / PEOPLE MODEL id: <string> id: <string> title:

    <string> first_name: <string> body: <string> last_name: <string> created: <datetime>
  4. GET /articles/1 HTTP/1.1 { "data": { "type": "articles", "id": "1",

    "attributes": { "title": "Hello world", "body": "bla bla bla", "created": "2016-01-10T14:00:02+01:00" } } }
  5. GET /articles/1 HTTP/1.1 { "data": { "type": "articles", "id": "1",

    "attributes": { "title": "Hello world", "body": "bla bla bla", "created": "2016-01-10T14:00:02+01:00" }, "relationships": { "author": { "links": { "self": "http://example.com/articles/1/relationships/author", "related": "http://example.com/articles/1/author" } } } } }
  6. GET /articles/1?include=author HTTP/1.1 { "data": { "type": "articles", "id": "1",

    "attributes": { : }, "relationships": { "author": { "links": { "self": "http://example.com/articles/1/relationships/author", "related": "http://example.com/articles/1/author" }, "data": { "type": "people", "id": "9" }, } } } "included": [] }
  7. GET /articles/1?include=author HTTP/1.1 { "data": { : }, "included": [

    { "type": "people", "id": "9", "attributes": { "first_name": "Joe", "last_name": "Smith" } } ] }
  8. ERRORS HTTP/1.1 422 Unprocessable Entity Content-Type: application/vnd.api+json { "errors": [

    { "status": "422", "source": { "pointer": "/data/attributes/first-name" }, "title": "Invalid Attribute", "detail": "First name must contain at least three characters." } ] }
  9. NEOMERX/JSON-API 01 $encoder = Encoder::instance([ 02 ArticleModel::class => ArticleSchema::class 03

    AuthorModel::class => AuthorSchema::class 04 ], 05 new EncoderOptions($encodeOptions, 'http://example.com') 06 ); 07 08 return $encoder->encodeData($articles);
  10. 01 class ArticleSchema extends SchemaProvider 02 { 03 protected $resourceType

    = 'articles'; 04 05 public function getId($article) 06 { 07 return $article->getId(); 08 } 09 10 public function getAttributes($article) 11 { 12 return [ 13 'title' => $article->getTitle(), 14 'body' => $article->getBody(), 15 'created' => $article->getCreated() 16 ]; 17 } 18 19 public function getRelationships($article, array $includeList = []) 20 { 21 return [ 22 'author' => [self::DATA => $article->getAuthor()], 23 ]; 24 } 25 }
  11. EMBER-DATA - ARTICLE.JS import DS from 'ember-data'; export default DS.Model.extend({

    title: DS.attr('string'), body: DS.attr('string'), created: DS.attr('date'), author: DS.belongsTo('person') });
  12. EMBER-DATA - PERSON.JS import DS from 'ember-data'; export default DS.Model.extend({

    first_name: DS.attr('string'), last_name: DS.attr('string'), articles: DS.hasMany('article') });