@steveklabnik
The Zen of Python: explicit is better than implicit
Ruby on Rails: Convention over configuration
GET /
Host: steveklabnik.com
$ curl -I steveklabnik.com
HTTP/1.1 200 OK
Content-Type: text/html
text/plain
text/html
application/json
image/png
Media types are explicit conventions.
Media types are explicit because we have Content-Type
and the related RFC.
Media types are conventions because we have a shared understanding of processing rules.
application/json
JavaScript Object Notation (JSON) is a lightweight, text-based, language-independent data interchange format. It was derived from the ECMAScript Programming Language Standard. JSON defines a small set of formatting rules for the portable representation of structured data.
JSON's minimalism can only encode the vague structure of your data.
This has led to an explosion of bespoke, artisanal, hand-crafted APIs.
The purpose of the Content-Type field is to describe the data contained in the body fully enough that the receiving user agent can pick an appropriate agent or mechanism to present the data to the user, or otherwise deal with the data in an appropriate manner.
Any sufficiently advanced API contains an ad-hoc, informally specified implementation of some media type that extends JSON.
application/json
leads to bikeshedding. Bikeshedding leads to anger. Anger leads to hate. Hate leads to suffering.
JSON API assumes that you have some collection of data
that you'd like to synchronize across a network boundary.
Its conventions allow you to build
a smart client that minimizes requests.
It's based on real code used by real sites.
We use it at my employer to process payments.
If it's good enough for money, it's good enough for your API.
It's co-authored by Yehuda Katz and myself.
Here's what JSON API (in the ID style) looks like:
{
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "9",
"comments": [ "5", "12", "17", "20" ]
}
}]
}
and in the URL style:
{
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "http://example.com/people/1",
"comments": "http://example.com/comments/5,12,17,20"
}
}]
}
URI Templates:
{
"links": {
"posts.comments": "http://example.com/posts/{posts.id}/comments"
},
"posts": [{
"id": "1",
"title": "Rails is Omakase"
}, {
"id": "2",
"title": "The Parley Letter"
}]
}
Not just for GET
GET /photos
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"photos": [{
"id": "1",
"title": "Mustaches on a Stick"
"src": "http://example.com/images/mustache.png"
}]
}
Not just for GET
POST /photos
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
"photos": [{
"title": "Ember Hamster",
"src": "http://example.com/images/productivity.png"
}]
}
Not just for GET
GET /photos
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"photos": [{
"id": "1",
"title": "Mustaches on a Stick"
"src": "http://example.com/images/mustache.png"
}, {
"id": "2",
"title": "Ember Hamster",
"src": "http://example.com/images/productivity.png"
}]
}