The echelon.solutions API handbook describing best practices for API development and management.
Please submit an issue to ask a question or start a community discussion around best practices. Open a pull request to have your additions or edits reviewed.
This document can also be viewed at the GitHub Pages site.
Contents
TLS should be required for all endpoints, without exception.
Every REST API must at least accept basic authentication. Both protected and public resources should be marked and documented as such.
The REST APIs should not handle authorization. Authorization is a service layer concern that ensures that the authenticated client has the correct permissions to access the requested resource.
Here is a document containing the HTTP response code specification. An appropriate HTTP status code should be returned for every response.
For successful responses, here is a general guideline:
200
: Request succeeded; appropriate for synchronousGET
/DELETE
/PATCH
calls.201
: Request succeeded; appropriate for synchronousPOST
calls that involve resource creation.202
: Request accepted; appropriate for asynchronousPOST
/DELETE
/PATCH
calls.206
: Request succeeded; appropriate forGET
calls that return only a partial response.
Always use a consistent error response structure. This response should at the very least include a machine-readable error id
and a human readable error message
. All error response scenarios should be included as part of the API documentation.
Preferably, also include a developer-readable developerMessage
and a url
directing the client to further documentation about the error and how to resolve it. For example:
HTTP/1.1 429 Too Many Requests
{
"id": "rate_limit",
"message": "Maximum number of requests.",
"developerMessage": "This account reached the maximum API rate limit.",
"url": "https://api.example.com/docs/rate-limits"
}
Each resource should have an id
attribute. Use only globally unique identifiers that are unique across instances of the service and across resources of the service. This can be accomplished using UUIDs, for example:
"id": "01234567-89ab-cdef-0123-456789abcdef"
Resources should also include created_at
and updated_at
timestamps by default, where applicable.
To support client caching, be sure to include an ETag
header in all responses that identifies the version of the returned resource. Clients can check for staleness by supplying the ETag
header value in the If-None-Match
header in subsequent requests.
Accept and return times in UTC only, specifically in ISO8601
format. For example:
"updated_at": "2012-01-01T12:00:00Z"
Nest foreign key relationships by serializing the foreign object rather than including an identifier field. This approach allows adding more information about the related resource without having to change the structure of the top-level response.
For example, this is preferred:
{
"title": "How to document an API",
"author": {
"id": "01234567",
"name": "John Doe"
}
}
This is not:
{
"title": "How to document an API",
"authorId": "01234567"
}
Use the Accepts
header with a custom content type. This has the added benefit of pegging a specific request object version as well as an API version. For example:
application/vnd.blog.post+json; version=2
Alternatively, rather than using the Accepts Header approach, the version of the API appears in the URL. For example:
https://api.example.com/v1/posts
HATEOAS: Hypermedia as the engine of application state
Hypermedia is links and metadata for operations that help developers or machines perform additional actions.
“If you look at hypermedia as a recipe of how the next request is supposed to look like, you will grasp what hypermedia is all about” (Read more at http://nordicapis.com/designing-a-true-rest-state-machine/)
Much of the content of this API handbook can be attributed to a collection of fine resources. Here they are mentioned below for further and supplemental reading: