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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Dan Gebhardt
October 16, 2019
5
820
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
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
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.2k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
0
180
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.5k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
76
The Limits of Empathy - UXLibs8
cassininazir
1
270
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.3k
How to Ace a Technical Interview
jacobian
281
24k
The browser strikes back
jonoalderson
0
830
Marketing to machines
jonoalderson
1
5k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
400
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