Blog

API Design

Some notes on REST API design


Recently I have been reading about good practices for REST API’s design. This post is basically a summary of some useful rules/tips taken from:

What is a REST API ?

So (obviously) REST API is an API that satisfies REST architecture constraints. (wow, that was totally unexpected)

I don’t think its very useful to go over what the REST constraints are. Mostly because they are a subject of debate.

In practice, devs refer to REST APIs as a way to communicate with a program through HTTPS.

So, what do we need to develop good APIs?

Accept and respond with JSON

Part of the REST debate mentioned argues that you should use HTML and not JSON. But, in practice, everybody expects to communicate with your API using JSON, it’s the standard now. The only exception its FormData used when you need to send files.

Nouns for endpoint paths, not verbs

The nouns represent the entity that the endpoint is retrieving or manipulating. The verb is in the HTTP request method (GET, POST, PUT, DELETE).

Logical nesting on endpoints

Endpoints paths follow a hierarchy where elements on the left are considered “parents” and elements on the right are “children”. E.g: If you want to get the comments of an article you would use /articles/:articleId/comments and not /comments/:articleId/. Mirroring your database is not necessarily good.

But nesting shouldn’t go too far, after the second or third level, nested endpoints can get annoying. Consider returning the URL to those resources instead.

{
  "id": "1",
  "comment": "Pretty good article",
  "author": "/user/2" // /user/:userId
}

Handle errors gracefully and return standard error codes

Use HTTP Error codes and add descriptive messages in your responses. Don’t be overly descriptive, attackers can use the error content.

Avoid sending a response with status 200 and a message explaining the error, embrace the native error handling.

Allow filtering, sorting, and pagination

Databases behind REST APIs can get very large. Sending all the data at once can be slow and/or bring down our systems.

The more data in the database, the more important filtering, sorting and pagination becomes.

The common pattern is to use query parameters to filter, paginate or sort a resource. E.g.: /resource?filter=value&page=1&sort=-datepublished → filtered by “value”, page 1, sorted descending by date (- means descending, + means ascending).

Good security practices

This is quite straightforward:

Security cannot be reduced to those two points, but those are quick wins. Try to follow the best security practices whenever you can and don’t neglect them.

Cache data to improve performance

There are many kinds of caching solutions. Cache can reduce queries to the database and make data fetching faster. The cost is to make debugging more difficult. If you use caching, include Cache-Control information in your headers. This will help users effectively use your caching system.

Versioning our APIs

We can just add the version number to the start of the endpoint URL path to version them: /v2/employees. This will allow older versions of the API to keep working.