Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
An Introduction to the JSON:API Specification
Search
Dan Gebhardt
October 16, 2019
830
5
Share
An Introduction to the JSON:API Specification
Presented at the API Specifications Conference in Vancouver, BC.
Dan Gebhardt
October 16, 2019
More Decks by Dan Gebhardt
See All by Dan Gebhardt
Worker power!
dgeb
0
500
Modern Ember
dgeb
0
160
The Future of Data in Ember
dgeb
0
460
Give Apps Online Superpowers by Optimizing them for Offline
dgeb
2
220
Overview of Orbit.js
dgeb
0
120
Introducing Ember Engines
dgeb
4
3.7k
Introducing JSON API
dgeb
5
740
Fault Tolerant UX
dgeb
4
970
Ambitious Data Flows with Ember.js and Orbit.js
dgeb
10
1.6k
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
100
Bash Introduction
62gerente
615
210k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
510
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8k
Optimizing for Happiness
mojombo
378
71k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
710
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
140
30 Presentation Tips
portentint
PRO
1
270
Ruling the World: When Life Gets Gamed
codingconduct
0
190
Transcript
An introduction to Dan Gebhardt (@dgeb) Cerebris Corporation
None
None
None
"A Specification for Building APIs in JSON"
"A Specification for Fetching and Mutating a Graph of Data"
"A representation of resources and their relationships" Graph
application/vnd.api+json
Yehuda Katz @wycats Editors Dan Gebhardt @dgeb Gabe Sullice @gabesullice
History • 2013 - Initial draft released by Yehuda Katz
• 2015 - v1.0 released • 2018 - v1.1 draft released • 2019 - v1.1 progress continues ...
None
None
None
None
None
"The JSON:API Specification" or "jsonapi.org"
None
None
" " " "
application/vnd.api+json
application/vnd.api+json
application/vnd.[org]+json
Sample of organizations that have either public APIs or public
OSS projects that support JSON:API application/vnd.[org]+json
Sample of organizations that have either public APIs or public
OSS projects that support JSON:API application/vnd.api+json
application/vnd.hal+json application/vnd.siren+json application/vnd.collection+json
application/???+json
None
Benefits
Benefits • Shared conventions • Shared tooling • Standards-based best
practices • Plays well with others • Gradual adoption
Benefits • Shared conventions • Shared tooling • Standards-based best
practices • Plays well with others • Gradual adoption
Shared conventions
Document structure + Processing rules Shared conventions
Document structure
{ "data": {} | [{}] | null, "included": {}, "links":
{}, "meta": {}, "jsonapi": {}, "errors": [{}] } Top-level structure
{ "data": {} | [{}] | null, "included": {}, "links":
{}, "meta": {}, "jsonapi": {}, "errors": [{}] } Top-level structure }All optional Specific combinations disallowed
{ "data": {} | [{}] | null } Top-level structure
{ "data": {} | [{}] | null, "included": {}, "links":
{}, "meta": {} } Top-level structure
{ "errors": [{}] } Top-level structure
Primary data { "data": {} | [{}] | null }
{ "data": { "type": "article", "id": "123", "attributes": { "title":
"Introduction to JSON:API", "published": "2019-10-11" } } }
{ "data": [{ "type": "article", "id": "123", "attributes": { "title":
"Introduction to JSON:API", "published": "2019-10-11" } }, { "type": "article", "id": "124", "attributes": { "title": "Retrospective on ASC 2019", "published": "2019-10-15" } }] }
{ "type": "article", "id": "123" } Resource object
{ "type": "article", "id": "123" } Resource object }Also called
a "Resource Identity Object" in its simplest form
{ "type": "article", "id": "123", "attributes": { // ... this
article's attributes }, "relationships": { // ... this article's relationships }, "links": { // ... links to this article }, "meta": { // ... metadata about this article } }
{ "type": "article", "id": "123", "attributes": { "title": "Hello ASC
2019!" }, "relationships": { "author": { "links": { "self": "/articles/123/relationships/author", "related": "/articles/123/author" } } } }
{ "links": { "self": "/articles/123/relationships/author", "related": "/articles/123/author" } } Relationship
object
{ "links": { "self": "/articles/123/relationships/author", "related": "/articles/123/author" }, "meta": {
"created": "2019-10-15T18:13:25Z" } } Relationship object
{ "links": { "self": "/articles/123/relationships/author", "related": "/articles/123/author" }, "meta": {
"created": "2019-10-15T18:13:25Z" }, "data": { "type": "person", "id": "123" } } Relationship object
{ "links": { "self": "/articles/123/relationships/author", "related": "/articles/123/author" }, "meta": {
"created": "2019-10-15T18:13:25Z" }, "data": { "type": "person", "id": "123" } } Relationship object }Resource identity object(s), or "Linkage data"
{ "data": [{ "type": "article", "id": "123", "relationships": { "author":
{ "data": { "type": "person", "id": "abc" } } } }], "included": [{ "type": "person", "id": "abc", "attributes": { "name": "Dan Gebhardt" } }] } Compound Document
{ "data": [{ "type": "article", "id": "123", "relationships": { "author":
{ "data": { "type": "person", "id": "abc" } } } }], "included": [{ "type": "person", "id": "abc", "attributes": { "name": "Dan Gebhardt" } }] } Compound Document
{ "data": [ { "type": "article", "id": "1", "attributes": {
"title": "JSON:API paints my bikeshed!" }, "relationships": { "author": { "data": { "type": "person", "id": "9" } }, "comments": { "data": [ { "type": "comments", "id": "5" } ] } } } ], // continued ... // ... continued "included": [ { "type": "person", "id": "9", "attributes": { "name": "Dan Gebhardt" } }, { "type": "comments", "id": "5", "attributes": { "body": "First!" }, "relationships": { "author": { "data": { "type": "person", "id": "9" } } } } ] }
{ "data": [ { "type": "article", "id": "1", "attributes": {
"title": "JSON:API paints my bikeshed!" }, "relationships": { "author": { "data": { "type": "person", "id": "9" } }, "comments": { "data": [ { "type": "comments", "id": "5" } ] } } } ], // continued ... // ... continued "included": [ { "type": "person", "id": "9", "attributes": { "name": "Dan Gebhardt" } }, { "type": "comments", "id": "5", "attributes": { "body": "First!" }, "relationships": { "author": { "data": { "type": "person", "id": "9" } } } } ] }
Links { "links": { "self": "/articles/123" } }
Links { "links": { "self": "/articles/123", "doSomething": { "href": "/articles/123/doSomething",
"meta": { "note": "POST to do something" } } } }
Links { "links": { "self": "/articles/123", "doSomething": { "href": "/articles/123/doSomething",
"meta": { "note": "POST to do something" } } } } }Allowed links locations: • Top-level • Resource objects • Relationship objects • Error objects
{ "meta": { "whatever": "you want", "can": { "go": "in
meta" } } } Metadata
{ "meta": { "whatever": "you want", "can": { "go": "in
meta" } } } Metadata }Allowed metadata locations: • Top-level • Resource objects • Resource identity objects • Link objects • Error objects
Document structure + Processing rules Shared conventions
Processing rules
Opinionated HTTP usage
Opinionated HTTP usage • GET • POST • PATCH •
DELETE • Resources • Relationships
• GET • POST • PATCH • DELETE • Resources
• Relationships Opinionated HTTP usage
• GET • POST • PATCH • DELETE • Resources
• Relationships Opinionated HTTP usage
Fetching GET /articles GET /articles/123 Note: URL Structure is not
dictated by JSON:API
Graph Fetching GET /articles?include=author GET /articles?include=comments,author GET /articles?include=comments.author,author
Sparse Fieldsets GET /articles?fields=title,author GET /articles?include=author& fields[article]=title,author& fields[person]=name
Sorting GET /people?sort=age GET /people?sort=age,name GET /people?sort=-lastUpdated,name
Pagination GET /people?page[???]=x }Pagination strategy agnostic: • Page-based • Cursor-based
Filtering GET /people?filter[???]=x }Filtering strategy agnostic: • Simple, strict match
• Nested conditions • Vertical-specific filtering
• GET • POST • PATCH • DELETE • Resources
• Relationships Opinionated HTTP usage Documented at jsonapi.org
Benefits • Shared conventions • Shared tooling • Standards-based best
practices • Plays well with others • Gradual adoption
Shared tooling
None
Server • Swift • PHP • Node.js • Ruby •
Python • Go • .NET • Java • JavaScript • Typescript • iOS • Ruby • PHP • Dart • Perl Client Libraries • Scala • Elixir • Haskell • Perl • Vala • Rust • Dart • Java • Android • R • Elm • .NET • Python • Elixir 74 93
Server netflix/fast_jsonapi google/jsonapi drupal/jsonapi cerebris/jsonapi-resources rails-api/active_model_serializers neomerx/json-api emberjs/data orbitjs/orbit crnk-project/crnk-framework
jsonapi-ios/Spine reststate/Mobx reststate/Vuex Client Libraries
Benefits • Shared conventions • Shared tooling • Standards-based best
practices • Plays well with others • Gradual adoption
Standards-based best practices
Composition of standards • HTTP (RFC7231) • JSON (RFC8259) •
URI (RFC3986) • Profiles (RFC6906) • Web linking (RFC8288) • UUID (RFC4122) • And more ...
Composition of standards Evolution with those standards
Composition of standards Benefit from ecosystems that support those standards
Benefits • Shared conventions • Shared tooling • Standards-based best
practices • Plays well with others • Gradual adoption
Plays well with others • OpenAPI • JSON Schema •
JSON-LD • And more ...
Benefits • Shared conventions • Shared tooling • Standards-based best
practices • Plays well with others • Gradual adoption
You MAY use feature X. Gradual adoption If you detect
feature X, you MUST do A, B, and C.
Source: https://martinfowler.com/articles/richardsonMaturityModel.html Gradual adoption
JSON:API v1.1
JSON:API v1.1 • Profiles • Extensions • Expanded hypermedia controls
Profiles Extensions Specify meaning for members already reserved for users.
Specify meaning for members reserved for the spec itself.
Profiles Extensions Negotiated with the `profile` media type parameter. Negotiated
with the `ext` media type parameter.
Profiles Extensions May be ignored by servers. Must be supported
or else error.
POST /bulk HTTP/1.1 Host: example.org Content-Type: application/vnd.api+json;ext="https://jsonapi.org/ext/atomic" Accept: application/vnd.api+json;ext="https://jsonapi.org/ext/atomic" {
"atomic:operations": [{ "op": "add", "href": "/blogPosts", "data": { "type": "articles", "attributes": { "title": "JSON API paints my bikeshed!" } } }] } Extension: Atomic Operations Experimental
HTTP/1.1 200 OK Content-Type: application/vnd.api+json;ext="https://jsonapi.org/ext/atomic" { "atomic:results": [{ "data": {
"links": { "self": "http://example.com/blogPosts/13" }, "type": "articles", "id": "13", "attributes": { "title": "JSON API paints my bikeshed!" } } }] } Extension: Atomic Operations Experimental
{ "atomic:operations": [{ "op": "add", "data": { "type": "authors", "id":
"acb2ebd6-ed30-4877-80ce-52a14d77d470", "attributes": { "name": "dgeb" } } }, { "op": "add", "data": { "type": "articles", "id": "bb3ad581-806f-4237-b748-f2ea0261845c", "attributes": { "title": "JSON API paints my bikeshed!" }, "relationships": { "author": { "data": { "type": "authors", "id": "acb2ebd6-ed30-4877-80ce-52a14d77d470" } } } } }] } }Multiple linked operations Experimental
Expanded hypermedia controls
None
Beyond JSON:API v1.1
Beyond JSON:API v1.1 • Optimize for HTTP/2/3 • More extensions!
More experiments! • Focus on DX via tooling (e.g. spectral rulesets)
HTTP/1.1 Includes GET /articles?include=author GET /articles?include=comments,author GET /articles?include=comments.author,author
HTTP/2 Server Push GET /articles?serverPush=author GET /articles?serverPush=comments,author GET /articles?serverPush=comments.author,author Experimental
HTTP/2 Server Push Experimental
Resources
None
None
None
None
None
An introduction to Dan Gebhardt (@dgeb) Cerebris Corporation
An introduction to Dan Gebhardt (@dgeb) Cerebris Corporation Thanks! jsonapi.org
@jsonapi