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

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
James Higginbotham

Founder of LaunchAny and author of Principles of Web API Design. James helps enterprises build API platforms and get them ready for AI.