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

Getting to JSON:API: What it is, why you should use it, and how to use it in Laravel

Matt Stauffer
February 26, 2020

Getting to JSON:API: What it is, why you should use it, and how to use it in Laravel

Getting to JSON:API: What it is, why you should use it, and how to use it in Laravel

Matt Stauffer

February 26, 2020
Tweet

More Decks by Matt Stauffer

Other Decks in Technology

Transcript

  1. HOW TO JSON:API
    QUICKLY & EASILY
    IN LARAVEL
    Getting to JSON:API - Matt Stauffer

    View Slide

  2. You can't.
    THE END
    Getting to JSON:API - Matt Stauffer

    View Slide

  3. GETTING TO JSON:API
    WHAT IT IS, WHY YOU SHOULD USE IT, and
    HOW TO USE IT IN LARAVEL
    Getting to JSON:API - Matt Stauffer

    View Slide

  4. First half: Theory
    ▸ 1. Intro to REST APIs
    ▸ 2. The State of APIs
    ▸ 3. What is JSON:API?
    ▸ 4. Why JSON:API?
    Getting to JSON:API - Matt Stauffer

    View Slide

  5. Second half: Implementation
    ▸ 5. JSON:API Tooling in Laravel
    ▸ 6. Other API concerns
    ▸ 7. After the talk
    ▸ 8. Outro
    Getting to JSON:API - Matt Stauffer

    View Slide

  6. PART 1
    Intro to
    REST APIS
    Getting to JSON:API - Matt Stauffer

    View Slide

  7. REST: CRUD over JSON using HTTP verbs
    Getting to JSON:API - Matt Stauffer

    View Slide

  8. REST: CRUD over JSON using HTTP verbs
    shaped like /dogs/14 and stuff
    Getting to JSON:API - Matt Stauffer

    View Slide

  9. What's "REST", anyway?
    Getting to JSON:API - Matt Stauffer

    View Slide

  10. REPRESENTATIONAL
    STATE
    TRANSFER
    Getting to JSON:API - Matt Stauffer

    View Slide

  11. ROY FIELDING
    Getting to JSON:API - Matt Stauffer

    View Slide

  12. REST is:
    ▸ Client/server
    ▸ Stateless
    ▸ Cacheable
    ▸ Layered (proxyable, load balanceable)
    ▸ Uniform Interface:
    ▸ Resource identification in requests
    ▸ Resource manipulation through representations
    ▸ Self-descriptive messages (content headers)
    ▸ Hypermedia as the Engine of Application State
    Getting to JSON:API - Matt Stauffer

    View Slide

  13. REST misconceptions:
    ▸ REST has no preferred URL patterns
    ▸ REST needn't be JSON
    ▸ Most REST-ish APIs aren't actually RESTful, but that's fine
    Getting to JSON:API - Matt Stauffer

    View Slide

  14. What's "HATEOAS"?
    Getting to JSON:API - Matt Stauffer

    View Slide

  15. What's "HATEOAS"?
    Getting to JSON:API - Matt Stauffer

    View Slide

  16. What's "HATEOAS"?
    HYPERMEDIA AS THE ENGINE
    OF APPLICATION STATE
    Getting to JSON:API - Matt Stauffer

    View Slide

  17. What's "HYPERMEDIA"?
    Getting to JSON:API - Matt Stauffer

    View Slide

  18. AN EXAMPLE OF EMBEDDED HYPERMEDIA
    /* GET /departments/10 */
    {
    "type": "departments",
    "id": "10",
    "attributes": {
    "name": "Information Technology"
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  19. AN EXAMPLE OF EMBEDDED HYPERMEDIA
    /* GET /departments/10 */
    {
    "type": "departments",
    "id": "10",
    "attributes": {
    "name": "Information Technology"
    },
    "links": [
    {
    "href": "departments/10/employees",
    "rel": "employees",
    "type" : "GET"
    }
    ]
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  20. APIS AS STATE MACHINES
    Getting to JSON:API - Matt Stauffer

    View Slide

  21. SHOULD WE AIM FOR TRUE HATEOAS?
    Getting to JSON:API - Matt Stauffer

    View Slide

  22. "Hard coding URIs in your documentation and thus also in all of the
    clients of your API, is a clear violation of the REST constraint that
    hypermedia must be the engine of application state."
    - Asbjørn Ulsberg
    Getting to JSON:API - Matt Stauffer

    View Slide

  23. SHOULD WE AIM FOR TRUE HATEOAS?
    PROBABLY NOT.
    Getting to JSON:API - Matt Stauffer

    View Slide

  24. Getting to JSON:API - Matt Stauffer

    View Slide

  25. Getting to JSON:API - Matt Stauffer

    View Slide

  26. GRADUAL ADOPTION.
    Getting to JSON:API - Matt Stauffer

    View Slide

  27. PART 2
    THE STATE OF APIS
    Getting to JSON:API - Matt Stauffer

    View Slide

  28. WE'RE IN THE BAD OLD DAYS
    WHEN IT COMES TO API STANDARDIZATION
    Getting to JSON:API - Matt Stauffer

    View Slide

  29. Getting to JSON:API - Matt Stauffer

    View Slide

  30. “Every sufficiently advanced API contains an ad hoc, informally-
    specified implementation of some media type on top of JSON.”
    - Steve Klabnik
    Getting to JSON:API - Matt Stauffer

    View Slide

  31. APIS ARE A
    BIKESHEDDER'S PARADISE
    Getting to JSON:API - Matt Stauffer

    View Slide

  32. BIKESHEDDING
    Wasting time and energy
    on marginal technical issues.
    Getting to JSON:API - Matt Stauffer

    View Slide

  33. STOP WASTING TIME
    BIKESHEDDING ON API STANDARDS
    Getting to JSON:API - Matt Stauffer

    View Slide

  34. PART 3
    WHAT IS JSON:API?
    Getting to JSON:API - Matt Stauffer

    View Slide

  35. A LITTLE HISTORY:
    Ember ❤ Rails
    Getting to JSON:API - Matt Stauffer

    View Slide

  36. IT'S A STANDARD
    Getting to JSON:API - Matt Stauffer

    View Slide

  37. Getting to JSON:API - Matt Stauffer

    View Slide

  38. YOU MAY BE FAMILIAR...
    {
    "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
    // ... this article's attributes
    },
    "relationships": {
    // ... this article's relationships
    }
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  39. BUT WHAT ABOUT...
    ▸ Compound documents in flat included key
    ▸ Content negotiation requirements
    ▸ Custom error syntax
    ▸ Nested include directives
    ▸ Sparse fieldsets
    ▸ Create/update/delete validation
    ▸ Relationship modification endpoints
    Getting to JSON:API - Matt Stauffer

    View Slide

  40. !
    Getting to JSON:API - Matt Stauffer

    View Slide

  41. THE BIG PIECES OF JSON:API
    Getting to JSON:API - Matt Stauffer

    View Slide

  42. THE BIG PIECES OF JSON:API
    ▸ Document structure
    ▸ HTTP standards
    Getting to JSON:API - Matt Stauffer

    View Slide

  43. THE BIG PIECES PART 1:
    DOCUMENT STRUCTURE
    Getting to JSON:API - Matt Stauffer

    View Slide

  44. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  45. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  46. {
    "jsonapi": {
    "version": "1.0"
    },
    "meta": {
    "i can do anything": {
    "i want": ["in", "here"]
    }
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  47. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  48. {
    "data": {
    "type": "articles",
    "id": "1",
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  49. {
    "data": [{
    "type": "articles",
    "id": "1"
    },{
    "type": "articles",
    "id": "42"
    }]
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  50. THE STRUCTURE OF A
    RESOURCE OBJECT
    Getting to JSON:API - Matt Stauffer

    View Slide

  51. Resource identifier object
    {
    "type": "articles",
    "id": "1"
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  52. Optional sections
    {
    "type": "articles",
    "id": "1",
    "attributes": {
    // key/value pairs of all attributes
    },
    "relationships": {
    // relationship objects
    },
    "links": {
    // link objects
    },
    "meta": {
    // key/value pairs
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  53. Attributes
    {
    "type": "articles",
    "id": "1",
    "attributes": {
    "title": "The greatest post ever",
    "body": "Lorem ipsum"
    },
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  54. Relationships
    {
    "type": "articles",
    "id": "1",
    "relationships": {
    "author": {
    "data": {
    "type": "people",
    "id": "5"
    }
    }
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  55. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  56. COMPOUND DOCUMENTS
    {
    "data": {
    "type": "articles", "id": "123", "attributes": {},
    "relationships": {
    "author": { "data": { "type": "people", "id": "5" }}
    }
    },
    "included": [{
    "type": "people",
    "id": "5",
    "attributes": {
    "name": "Phil the GOAT"
    }
    }]
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  57. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  58. LINKS
    {
    "data": [{}, {}, {}],
    "links": {
    "self": "http://site.com/articles?page=3",
    "first": "http://site.com/articles?page=1",
    "prev": "http://site.com/articles?page=2",
    "next": "http://site.com/articles?page=4",
    "last": "http://site.com/articles?page=42"
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  59. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  60. ERRORS
    {
    "errors": [{
    "id": "SERVER500C1",
    "links": {},
    "status": "500",
    "code": "SERVER500C1",
    "title": "A server error has occurred.",
    "detail": "Longer message here.",
    "source": { /* Object containing references to the source */},
    "meta": {}
    }]
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  61. ERRORS
    {
    "errors": [{
    "status": "500",
    "title": "A server error has occurred."
    }]
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  62. DOCUMENT STRUCTURE IN JSON:API
    ▸ data
    ▸ included
    ▸ links
    ▸ errors
    ▸ meta
    ▸ jsonapi
    Getting to JSON:API - Matt Stauffer

    View Slide

  63. THE BIG PIECES PART 2:
    HTTP SPECS
    Getting to JSON:API - Matt Stauffer

    View Slide

  64. HTTP SPECS IN JSON:API
    ▸ Content Negotiation
    ▸ Verbs & Status Codes
    ▸ Query parameters (include, page, sort, filter, fields)
    Getting to JSON:API - Matt Stauffer

    View Slide

  65. CONTENT NEGOTIATION
    Getting to JSON:API - Matt Stauffer

    View Slide

  66. VERBS & STATUS CODES
    Use them. The way they were meant to be used.
    Note: If a JSON:API feature is requested and you don't support it (e.g. ?
    include), return a 400 BAD REQUEST
    Getting to JSON:API - Matt Stauffer

    View Slide

  67. QUERY PARAMETERS
    ▸ OPINIONATED:
    ▸ ?include=author,comments.author
    ▸ ?sort=created_at,-name
    ▸ ?fields[articles]=title,body&fields[people]=name
    ▸ UNOPINIONATED:
    ▸ ?page=5
    ▸ ?filter[abc]=def
    Getting to JSON:API - Matt Stauffer

    View Slide

  68. Important note:
    You don't have to fully adhere to a standard to learn from it.
    Getting to JSON:API - Matt Stauffer

    View Slide

  69. PART 4
    WHY JSON:API?
    Getting to JSON:API - Matt Stauffer

    View Slide

  70. WHY NOT OPENAPI?
    Getting to JSON:API - Matt Stauffer

    View Slide

  71. WHY NOT GRAPHQL?
    Getting to JSON:API - Matt Stauffer

    View Slide

  72. JSON:API: "A specification for Fetching
    and Mutating a Graph of Data"
    — Dan Gebhardt
    Getting to JSON:API - Matt Stauffer

    View Slide

  73. WHY NOT HAL, SIREN, JSON-LD,
    COLLECTION+JSON?
    Getting to JSON:API - Matt Stauffer

    View Slide

  74. WHY NOT HTTP/2?
    Getting to JSON:API - Matt Stauffer

    View Slide

  75. However...
    Getting to JSON:API - Matt Stauffer

    View Slide

  76. Getting to JSON:API - Matt Stauffer

    View Slide

  77. SO, WHY JSON:API?
    Stealing from Dan Gebhardt, co-editor of JSON:API:
    Getting to JSON:API - Matt Stauffer

    View Slide

  78. Getting to JSON:API - Matt Stauffer

    View Slide

  79. Getting to JSON:API - Matt Stauffer

    View Slide

  80. PART 5
    JSON:API TOOLING
    IN LARAVEL
    Getting to JSON:API - Matt Stauffer

    View Slide

  81. Which t l
    should I pick?
    Getting to JSON:API - Matt Stauffer

    View Slide

  82. https://github.com/tightenco/json-api-examples
    *Totally incomplete examples!
    Getting to JSON:API - Matt Stauffer

    View Slide

  83. Intro to
    ELOQUENT RESOURCES
    FOR JSON API
    Getting to JSON:API - Matt Stauffer

    View Slide

  84. class ArticleResource
    {
    public function toArray()
    {
    return [
    'data' => [
    'type' => 'articles',
    'id' => $this->resource->id,
    ],
    'attributes' => [
    'title' => $this->resource->title,
    ],
    ];
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  85. class ArticleController
    {
    public function index()
    {
    $articles = QueryBuilder::for(Article::class)
    ->allowedIncludes(['author', 'comments'])
    ->allowedSorts(['created_at', 'title'])
    ->paginate();
    return new ArticleCollection($articles);
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  86. Getting to JSON:API - Matt Stauffer

    View Slide

  87. !
    Getting to JSON:API - Matt Stauffer

    View Slide

  88. CONCLUSION
    Good for simple applications,
    but lots of work for full implementation.
    With Spatie Query Builder, you can get far.
    But no flat included.
    Getting to JSON:API - Matt Stauffer

    View Slide

  89. Getting to JSON:API - Matt Stauffer

    View Slide

  90. HOW DO I USE IT?
    https://github.com/tightenco/json-api-examples/tree/eloquent-
    resources
    Getting to JSON:API - Matt Stauffer

    View Slide

  91. Intro to
    FRACTAL FOR JSON API
    Getting to JSON:API - Matt Stauffer

    View Slide

  92. public function index()
    {
    $articles = QueryBuilder::for(Article::class)
    ->allowedIncludes(['author', 'comments'])
    ->allowedSorts(['created_at', 'title'])
    ->paginate(5);
    return fractal($articles, new ArticleTransformer)
    ->withResourceName('articles')
    ->respondJsonApi();
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  93. class AuthorTransformer extends TransformerAbstract
    {
    protected $defaultIncludes = [];
    protected $availableIncludes = ['articles'];
    public function transform(User $user)
    {
    return [
    'id' => (int) $user->id,
    'name' => $user->name,
    ];
    }
    public function includeArticles(User $user)
    {
    return $this->collection($user->articles, new ArticleTransformer, 'articles');
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  94. CONCLUSION
    Great for serializing even complex use cases,
    and great if you're a Fractal fan,
    but there's still manual work to be done.
    Also requires Spatie Query Builder to get far.
    Includes flat included for free.
    Getting to JSON:API - Matt Stauffer

    View Slide

  95. Getting to JSON:API - Matt Stauffer

    View Slide

  96. HOW DO I USE IT?
    https://github.com/tightenco/json-api-examples/tree/fractal
    Getting to JSON:API - Matt Stauffer

    View Slide

  97. Intro to
    LARAVEL-JSON-API
    FOR JSON API
    Getting to JSON:API - Matt Stauffer

    View Slide

  98. class Schema extends SchemaProvider
    {
    protected $resourceType = 'articles';
    public function getId($resource)
    {
    return (string) $resource->getRouteKey();
    }
    public function getAttributes($resource)
    {
    return [
    'title' => $resource->title,
    'body' => $resource->body,
    ];
    }
    public function getRelationships($resource, $isPrimary, array $includedRelationships)
    {
    return [
    'author' => [
    self::SHOW_SELF => true,
    self::SHOW_RELATED => true,
    self::SHOW_DATA => isset($includedRelationships['author']),
    self::DATA => function () use ($resource) {
    return $resource->author;
    },
    Getting to JSON:API - Matt Stauffer

    View Slide

  99. class Adapter extends AbstractAdapter
    {
    protected $attributes = [];
    protected $filterScopes = [];
    protected function author()
    {
    return $this->belongsTo('user');
    }
    protected function comments()
    {
    return $this->hasMany();
    }
    }
    Getting to JSON:API - Matt Stauffer

    View Slide

  100. CONCLUSION
    Steep learning curve,
    but the best way to get
    even close to full JSON:API.
    Getting to JSON:API - Matt Stauffer

    View Slide

  101. Getting to JSON:API - Matt Stauffer

    View Slide

  102. HOW DO I USE IT?
    https://howtojsonapi.com/laravel.html
    Getting to JSON:API - Matt Stauffer

    View Slide

  103. PART 6
    OTHER API CONCERNS
    Getting to JSON:API - Matt Stauffer

    View Slide

  104. AUTH
    ▸ Airlock
    ▸ Passport
    ▸ Simple token
    Getting to JSON:API - Matt Stauffer

    View Slide

  105. CACHING
    ▸ Cache DB requests
    ▸ Full HTTP request caching
    ▸ Intermediary caching (Varnish, Cloudflare)
    Getting to JSON:API - Matt Stauffer

    View Slide

  106. PART 7
    AFTER THE TALK
    Getting to JSON:API - Matt Stauffer

    View Slide

  107. ▸ Relationship endpoints
    ▸ True HATEOAS
    ▸ Etags & cache-control/expires
    ▸ JSON Schema for defining types (client-side validation!)
    ▸ HTTP/2 Server Push
    ▸ JSON:API 1.1
    Getting to JSON:API - Matt Stauffer

    View Slide

  108. PART 8
    OUTRO
    Getting to JSON:API - Matt Stauffer

    View Slide

  109. TL;DR
    ▸ API standards are great
    ▸ JSON:API is a great standard
    ▸ Gradual adoption means there are no judgments!
    ▸ If you don't adopt something, error if it's asked for
    ▸ Eloquent Resources/Fractal + Spatie Query Builder for JSON:API lite,
    Laravel-JSON-API for full spec
    Getting to JSON:API - Matt Stauffer

    View Slide

  110. RESOURCES
    Slides, links, and lists at:
    https://mattstauffer.com/json-api
    Getting to JSON:API - Matt Stauffer

    View Slide