Wesley Beary, a member of the API team at Heroku, has compiled a list of guidelines for creating HTTP+JSON APIs presented in a condensed form here.
The guide starts with a number of general recommendations:
- Require all API calls to use TLS. Reply with
403 Forbidden
to non-TLS ones - Always version an API. Use the
Accept
header to specify the version. Require clients to specify the API version instead of relying on a default one - Use the
ETag
header to support caching of resources - Identify each response with
X-Request-ID
; useful for logging or debugging purposes - Use
Range, Content-Range, Next-Range
to deal with large responses
For making requests, the guide mentions:
- Return appropriate status codes, such as:
200: SuccessfulGET
or synchronousDELETE, PATCH
201: Successful synchronousPOST
…
401: Unauthorized call
429: Too Many Requests
etc. - Return complete resources when available
- Accept serialized JSON in requests for symmetry with JSON responses
- Use consistent path formats. Resource names should use the plural form unless they refer to singletons
- Use lowercasing for paths and attributes to keep in line with host names
- Allow some resources, such as application names, to be specified by their name besides UUID
- Try to limit the depth of resource nesting by allocating them closer to the root path
When it comes to responses, Beary suggests:
- Use globally unique IDs for each resource
- Provide standard timestamps for resources
- For timestamps, use UTC in format ISO8601
- Nest foreign key relations to be able to include more details for the related resource without changing the structure of the response
- Provide detailed errors, including a machine readable ID, a human readable error message and an optional URL pointing to more details
- Establish a request rate limit and inform the client on the number of available request tokens with each response, using a header like
RateLimit-Remaining
- JSON should be minified in all responses
The guide includes more related advice:
- Provide the JSON schema in a machine readable format
- Include detailed APIs documentation for developers
- Allow developers to test the APIs
- APIs should be marked according to their stability status: prototype/development/production
We asked Beary how they came up with these guidelines and to explain some of them.
InfoQ: Have you had a guide from the beginning?
WB: I had some portions of the guide from early on, but they were pretty rough and lived only in my head. From my work on github.com/fog/fog and related things I had consumed many different APIs, which went a long way toward informing my opinions.
InfoQ: If you did not have the guide from the beginning, how did you develop the API? Through iterations?
WB: Lacking a more formal guide, it was definitely a process of iteration. Unfortunately, in addition to being somewhat slow, the iteration process was not scalable. It left me as a roadblock to adding new things. We built the guide to help distribute that decision making. We continue to iterate, but often it is now also on the guide itself. There are many ongoing discussions (github.com/interagent/http-api-design/issues) which continue to clarify and evolve the document as we learn more and other developers adopt it.
InfoQ: Why is it recommended to return the whole resource on a PUT or DELETE operation?
WB: Exceptional cases are the enemy in interfaces and guidelines. Sometimes the whole resource will be desired and leaving it out is mostly an optimization. I think having this as optional, opt-in behavior could make good sense in many cases, but having an easy, usable default is valuable. That said, this is a contentious point and there is some ongoing, deeper discussion about the pros and cons at https://github.com/interagent/http-api-design/issues/9.
InfoQ: Why using only UTC times formatted in ISO8601?
WB: Similar to returning the whole resource, having a consistent rule (without exceptions) makes it easier to reason about what you are doing and reduces the number of decisions you have to make when designing something. Also, time zones are crazy and terrible. I have lost count of the number of timezone related errors I have encountered and caused. In order to hopefully reduce the issues, we chose a known timezone and format to use throughout.