Presented at the API Specifications Conference in Vancouver, BC.
An introduction toDan Gebhardt (@dgeb)Cerebris Corporation
View Slide
"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@wycatsEditorsDan Gebhardt@dgebGabe Sullice@gabesullice
History• 2013 - Initial draft released by Yehuda Katz• 2015 - v1.0 released• 2018 - v1.1 draft released• 2019 - v1.1 progress continues ...
"The JSON:API Specification"or"jsonapi.org"
" " " "
application/vnd.[org]+json
Sample of organizations that have either public APIs or public OSS projects that support JSON:APIapplication/vnd.[org]+json
Sample of organizations that have either public APIs or public OSS projects that support JSON:APIapplication/vnd.api+json
application/vnd.hal+jsonapplication/vnd.siren+jsonapplication/vnd.collection+json
application/???+json
Benefits
Benefits• Shared conventions• Shared tooling• Standards-based best practices• Plays well with others• Gradual adoption
Shared conventions
Document structure+Processing rulesShared conventions
Document structure
{"data": {} | [{}] | null,"included": {},"links": {},"meta": {},"jsonapi": {},"errors": [{}]}Top-level structure
{"data": {} | [{}] | null,"included": {},"links": {},"meta": {},"jsonapi": {},"errors": [{}]}Top-level structure}All optionalSpecific 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": "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
Processing rules
Opinionated HTTP usage
Opinionated HTTP usage• GET• POST• PATCH• DELETE• Resources• Relationships
• GET• POST• PATCH• DELETE• Resources• RelationshipsOpinionated HTTP usage
FetchingGET /articlesGET /articles/123Note: URL Structure is not dictated by JSON:API
Graph FetchingGET /articles?include=authorGET /articles?include=comments,authorGET /articles?include=comments.author,author
Sparse FieldsetsGET /articles?fields=title,authorGET /articles?include=author&fields[article]=title,author&fields[person]=name
SortingGET /people?sort=ageGET /people?sort=age,nameGET /people?sort=-lastUpdated,name
PaginationGET /people?page[???]=x}Pagination strategy agnostic:• Page-based• Cursor-based
FilteringGET /people?filter[???]=x}Filtering strategy agnostic:• Simple, strict match• Nested conditions• Vertical-specific filtering
• GET• POST• PATCH• DELETE• Resources• RelationshipsOpinionated HTTP usageDocumented at jsonapi.org
Shared tooling
Server• Swift• PHP• Node.js• Ruby• Python• Go• .NET• Java• JavaScript• Typescript• iOS• Ruby• PHP• Dart• PerlClientLibraries• Scala• Elixir• Haskell• Perl• Vala• Rust• Dart• Java• Android• R• Elm• .NET• Python• Elixir7493
Servernetflix/fast_jsonapigoogle/jsonapidrupal/jsonapicerebris/jsonapi-resourcesrails-api/active_model_serializersneomerx/json-apiemberjs/dataorbitjs/orbitcrnk-project/crnk-frameworkjsonapi-ios/Spinereststate/Mobxreststate/VuexClientLibraries
Standards-based best practices
Composition of standards• HTTP (RFC7231)• JSON (RFC8259)• URI (RFC3986)• Profiles (RFC6906)• Web linking (RFC8288)• UUID (RFC4122)• And more ...
Composition of standardsEvolution with those standards
Composition of standardsBenefit from ecosystemsthat support those standards
Plays well with others• OpenAPI• JSON Schema• JSON-LD• And more ...
You MAY use feature X.Gradual adoptionIf you detect feature X, you MUST do A, B, and C.
Source: https://martinfowler.com/articles/richardsonMaturityModel.htmlGradual adoption
JSON:API v1.1
JSON:API v1.1• Profiles• Extensions• Expanded hypermedia controls
ProfilesExtensionsSpecify meaning for members already reserved for users.Specify meaning for members reserved for the spec itself.
ProfilesExtensionsNegotiated with the `profile` media type parameter.Negotiated with the `ext` media type parameter.
ProfilesExtensionsMay be ignored by servers.Must be supported or else error.
POST /bulk HTTP/1.1Host: example.orgContent-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 OKContent-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 operationsExperimental
Expanded hypermedia controls
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 IncludesGET /articles?include=authorGET /articles?include=comments,authorGET /articles?include=comments.author,author
HTTP/2 Server PushGET /articles?serverPush=authorGET /articles?serverPush=comments,authorGET /articles?serverPush=comments.author,authorExperimental
HTTP/2 Server Push Experimental
Resources
An introduction toDan Gebhardt (@dgeb)Cerebris CorporationThanks!jsonapi.org @jsonapi