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
5
760
An Introduction to the JSON:API Specification
Presented at the API Specifications Conference in Vancouver, BC.
Dan Gebhardt
October 16, 2019
Tweet
Share
More Decks by Dan Gebhardt
See All by Dan Gebhardt
Worker power!
dgeb
0
470
Modern Ember
dgeb
0
140
The Future of Data in Ember
dgeb
0
440
Give Apps Online Superpowers by Optimizing them for Offline
dgeb
2
200
Overview of Orbit.js
dgeb
0
100
Introducing Ember Engines
dgeb
4
3.5k
Introducing JSON API
dgeb
5
710
Fault Tolerant UX
dgeb
4
940
Ambitious Data Flows with Ember.js and Orbit.js
dgeb
10
1.6k
Featured
See All Featured
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
45
9.6k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
How GitHub (no longer) Works
holman
314
140k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Build The Right Thing And Hit Your Dates
maggiecrowley
35
2.7k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Docker and Python
trallard
44
3.4k
Git: the NoSQL Database
bkeepers
PRO
430
65k
Into the Great Unknown - MozCon
thekraken
39
1.8k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.9k
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