GlueCon 2013 Notes: Designing a Beautiful REST+JSON API – Les Hazlewood, CTO of Stormpath
Designing a Beautiful REST+JSON API – Les Hazlewood, CTO of Stormpath (@lhazlewood)
- REST is really hard (for providers)
- Guidelines and conventions can make it easy
- Resources are nouns, not verbs
- Should be course grained, not fine grained (or else the API will grow too large)
- Don’t do RPC-style (/getUser, /updateUser)
- HTTP verbs do not have to have a 1:1 correlation with create, read, update, delete
- GET = Read, DELETE = Delete, HEAD = Headers, no body
- PUT and POST can BOTH be used for create and update
- PUT can be used for create if the identifier/location is known by the client (e.g. /applications/clientSpecifiedId)
- PUT can be used for full replacement update (e.g. PUT /applications/existingId)
- Must contain the full replacement, making it idempotent on the server (meaning that the same state is the result of multiple calls with the same payload)
- POST can be used for create on a parent resource (e.g. POST /applications) – return a 201 created and set the Location header to the URL
- POST can be used as an update (e.g. POST /applications/a1b2c3) – return a 200 OK
- Media Types provide format specification + parsing rules
- Request: Accept header
- Response: Content-Type header
- application/json
- application/foo+json
- application/foo+json;application
- Very important to nail this (was mentioned early in Fielding’s thesis)
- Base URLs matter and convey a good (or bad) feeling about the support of your API
- Versioning – URL or Media-Type (e.g. application/jsonfoo;application&v=1)
- Media types for versioning isn’t obvious for new developers, but is more correct
- Resource Format can use the Media-Type (e.g. application/jsonfoo;bar=baz&v=1) but still in flux
- camelCase to support Javascript naming conventions and for easier consumption
- Timestamps – ISO 8601 using UTC
- HREF – distributed hypermedia is paramount!
- Every accessible resource has a unique URL
- Replaces IDs (IDs exist, but are opaque)
- Critical for linking
- Response Body
- GET is obvious, but what about POST?
- Return the representation in the response when feasible
- Add override (?body=false) for control when payloads may be large or rate limiting based on size
- Header
- Accept header, with values in order of preference
- Resource extensions
- /applications/a1b2c3.json, .csv, etc. can override accepts
- Hypermedia is paramount, linking is fundamental to scalability (not to performance, but to data scale and object graphs)
- Tricky in JSON, easy with XML (XLink)
- Use ‘href’ to mimic ref attribute in HTML links
- Reference Expansion (aka Link Expansion or Entity Expansion)
- Allows clients to control how much data they get back (e.f. x7y8z9?expand=directory)
- Representation can expand on ‘href’ approach with additional data (or not) and client can handle appropriately
- Pagination
- Offset/Limit (e.g. /accounts/x7y8z9/groups?offset=25)
- Many to Many
- Mappings should be a resource (GroupMembership for Accounts<–>Groups), allowing for future metadata to the resource
- Errors
- As descriptive as possible
- As much information as possible
- Developers are your customer
- Properties recommended: status (409), code (40925), property name, message, developerMessage, moreInfo (URL to docs for error code)
- Security
- Avoid server sessions
- Use standards (OAuth2, Basic auth over SSL only)
- Longer talk online: http://stormpath.com/blog/designing-rest-json-apis