The Elements of APIs

Requests and Responses

You’re using a RESTful HTTP architecture. The core tenet of this architecture is that incoming requests and outgoing responses are stateless and resource-oriented. TK explain what this means

Take advantage of the HTTP verbs. Use them consistently and with exclusive intent. We’ll get deep into what this means in practice in a future chapter.

Your verbs are GET for retrieving one or more resources; POST for creating one new resource; PATCH for updating one existing resource; and DELETE for deleting one existing resource. Don’t use any other verbs, and don’t use any of these verbs for anything other than what I’ve described here.

As I mentioned in the previous chapter, you have exactly three patterns of paths at your disposal.

A collection of resources of a given type are availble at a path that looks like /resource_type. For example, fetching Posts looks like GET /posts. You can GET this or POST to it. It supports pagination and filtering.

A single resource is identified with /resource_type/resource_id. You can GET, PATCH, and DELETE this.

The resource or resources linked to a given resource with a named relationship can be retrieved from /resource_type/resource_id/relationship_name. You can GET this.

Your responses should be JSON. They should be unsurprising and very flat.

You might be tempted to return graphs of data, either using something like GraphQL or simply offering deep webs of interconnected JSON data. Don’t do it. The flatter your structure is, the fewer options your clients have when trying to decide how to retrieve and manipulate your data. Small responses with few dependencies are also very easy to cache.

Use a consistent structure at the root of your responses. Your response bodies are always JSON objects. The object has a data key or an error key, but not both. If data is present, its value is a resource or an array of resources. If errors is present, it’s an array of strings describing what went wrong in human-friendly terms.

Responses with data have status codes in the 200 range. Responses with error have status codes in the 400-500 range.

Your GETs support a filter query parameter, which works for every attribute of the resource being retrieved.

Order of returned resources is well-defined and consistent, with documented default values. Order can be changed with an order query param, which is the name of an attribute on the resources, potentially with a leading hyphen. order=created_at returns your resources by creation date, oldest first. order=-updated_at returns your resources by update date, most recent first.

Pagination is cursor-based, or offset-based, or page-based, but it’s one style for everything. It uses one or two query params: cursor; offset and limit; or page and per_page. If you use cursor, your paginated response documents include a cursor key whose value can be used to retrieve the next page of results.

Your non-GET requests operate on one resource at a time.