Save 37% off PRO during our Black Friday Sale! »

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.

1fe0db7d2c3a6b8616d6b2e8ae0c0010?s=128

Henning Glatter-Götz

February 02, 2016
Tweet

Transcript

  1. {json:api} THE ULTIMATE ANTI-BIKESHEDDING WEAPON

  2. HENNING GLATTER-GÖTZ @hglattergotz

  3. Podcasting at ... HTTP://REACTIVE.AUDIO Panel discussions about current tech news

    with a focus on JavaScript
  4. ... and also podcasting at HTTP://DESCRIPTIVE.AUDIO Programmer origin stories

  5. {json:api}

  6. {"json":"api"}

  7. ASIDE FROM HTTP AND JSON WHAT DO MOST APIs HAVE

    IN COMMON?
  8. NOT MUCH!

  9. "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
  10. I DON'T NEED A STANDARD, I HAVE MY OWN THING!

  11. bikeshedding

  12. SEVERAL ATTEMPTS TO SOLVE THIS EXIST HAL, Siren, OData, JSON-API

  13. COVERED BY JSON-API SPEC Content Negotiation Document Structure Fetching Data

    Creating, Updating and Deleting Resources Query Parameters Errors HTTP status codes
  14. CONTENT NEGOTIATION Content-Type: application/vnd.api+json

  15. DOCUMENT STRUCTURE

  16. ARTICLES MODEL / PEOPLE MODEL id: <string> id: <string> title:

    <string> first_name: <string> body: <string> last_name: <string> created: <datetime>
  17. 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" } } }
  18. 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" } } } } }
  19. 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": [] }
  20. GET /articles/1?include=author HTTP/1.1 { "data": { : }, "included": [

    { "type": "people", "id": "9", "attributes": { "first_name": "Joe", "last_name": "Smith" } } ] }
  21. FETCHING DATA - SPARSE FIELD SETS GET /articles?fields[articles]=title,created HTTP/1.1 Accept:

    application/vnd.api+json
  22. FETCHING DATA - SORTING ascending GET /articles?sort=created HTTP/1.1 descending GET

    /articles?sort=-created,title HTTP/1.1
  23. 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." } ] }
  24. SO HOW DOES ANY OF THIS HELP US?

  25. tooling

  26. CLIENT LIBRARIES JavaScript, iOS, Ruby, PHP, Perl

  27. SERVER LIBRARIES PHP, Node.js, Ruby, Python, Go, .NET, Java, Elixir,

    Perl
  28. EXAMPLE BACKEND: NEOMERX/JSON-API (PHP) FRONTEND: EMBER-DATA (JavaScript)

  29. 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);
  30. 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 }
  31. 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') });
  32. 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') });
  33. WHO IS USING JSON-API? booking.com hood.ie patreon.com ember-data

  34. jsonapi.org discuss.jsonapi.org

  35. Thank You! If you want to talk more, feel free

    to contact me @hglattergotz henning@glatter-gotz.com