How to Design a REST API

Listen to this article

How to Design a REST API

Designing a REST API is not an easy task. Once you expose your API to the public, many people will be relying on your API as their data source which can be a tricky responsibility to have. In this article, we will walk you through the best practices of designing a REST API from scratch.

Why do we need an API?

Let’s say you have a data source such as a database that holds data that you want to fetch from multiple different clients. These clients might be web apps, mobile apps or maybe a scheduled data processing job. One way to solve this would be to simply let each client connect to the database, run queries and fetch the data that they need. While this might seem like an easy way to go there are some problems with this solution, namely:

  • Security. Each client needs to hold the database credentials which you do not want to reveal to any users at any cost.
  • Validation. Each client needs to implement its own validation of the data before it is stored in the database. If the validation logic is not standardized between the different services, the data might become out of sync.
  • Abstraction. If you would at some point want to change the database that stores the data, each client would have to be updated and perhaps completely rewritten to work with the new database.
  • Simplicity. Some data that you want to use in your clients might require a lot of different queries to be executed. These queries would have to be implemented in each of the clients for them to fetch the data.
  • Performance. If you let each client run its own database queries there is a risk that one of them executes heavy queries that risk overloading the database.

To avoid each of these clients having to interact with the database directly we want to build an abstraction layer on top of the database that makes it easy for these clients to connect and fetch the data that they need without having to write database queries and execute them directly towards the database. This abstraction layer is what we call an API.

An API can technically be accessed via any protocol but the most common one is HTTP over the internet. When we talk about a REST API you define each operation using a unique URL and HTTP verb. For example, to fetch a list of users from a REST API you might make the following HTTP request:

GET /users

This request would typically return a list of users:

[    {        “id”: 1,        “email”: “jane@example.com”    }]

To make a REST API easy to interact with for the clients that are consuming it we want to make sure that we design the API in a well thought out manner. This is especially important when designing REST APIs that are available to any third party client.

Formats

While it is possible to return data from an API in any format that can be sent over HTTP it is best practice to use a standardized format that is widely supported by different client libraries.

The most common format today is JSON (JavaScript Object Notation). This format can be easily consumed by all major programming languages. Below is an example of a simple JSON payload:

{    “id”: 1,    “email”: “jane@example.com”}

Another common, although declining, format is XML. The above JSON payload can be represented in XML as per below:

<?xml version=”1.0″ encoding=”UTF-8″?>
<user>
<email>jane@example.com</email>
<id>1</id>
</user>

While the most important aspect of the format that you choose for your API is that it is standardized across your entire API it is also advisable to go with one that is widely used and supported, such as JSON. It is also possible to build the API in a way that enables the client to choose which format is returned by passing a header for example. In this way, you can support whichever format the client is most suited for.

Prototyping

Before you start developing your API, it can be a good idea to create a prototype API. This can be used to:

  • Determine what data is needed to fulfill the business requirements
  • Help you get early feedback from the development team
  • Help you structure your API responses in an effective way for your client applications

A prototype can in its most simple form be an API documentation that you can discuss and make changes to. However, in some cases, you want to start working with the API to get a feel for how it is used by client applications. To do this, there are many different fake JSON API tools available. These tools let you create APIs that can be called over HTTP and return fake data that you control. They can be a great way to start collecting feedback on your API even before it is implemented.

Naming Conventions

URLs

A REST API is accessed through a set of URLs. As mentioned earlier, fetching a list of users might be done with a request such as

GET /users

When fetching a single user, we need to pass an ID in the URL so that the API can fetch the correct user from the database. That request might look something like:

GET /users/1

Let’s say that, in our database, a user has many projects. These might be accessed for the user with ID 1 like this:

GET /users/1/projects

Choosing how these URLs are named is a very important aspect of designing a good REST API. With well thought out URLs client developers can easily recognize the patterns and keep developing without having to dig through the documentation too much.

The above naming convention is quite common where you fetch all entities with a pluralized path (/users) and a single entity with an appended ID (/users/1).

The most important thing regarding naming conventions is to make sure that all URLs that make up your API follow the same pattern, whichever one you choose.

Responses

There are multiple ways to format the reponses returned from your API. If we look at a slightly larger JSON API response, it might look like this:

{    “id”: 1,    “private_email”: “jane@example.com”,    “work_email”: “jane@acme.com”,    “first_name”: “Jane”,    “last_name”: “Anderson”}

In this example, the keys in the object are formatted according to the naming convention snake case. Using snake case, the keys are lower case and each word in the key is separated with an underscore. This format is quite common when working with languages such as Python, Ruby or PHP.

Another common format for APIs is camel case. Using camel case, each new word begins with a capital letter. The above example would look like this in camel case:

{    “id”: 1,    “privateEmail”: “jane@example.com”,    “workEmail”: “jane@acme.com”,    “firstName”: “Jane”,    “lastName”: “Anderson”}

I recommend you choose a common naming convention for your responses and stick with it across all of your API endpoints.

HTTP Status Codes

HTTP status codes can be used in your API responses to indicate the result of an operation. Commonly, a successful response is a 200 OK. The available HTTP response codes fall into one of the following categories:

  • Informational responses (100–199) e.g. 100 Continue
  • Successful responses (200–299) e.g. 200 OK
  • Redirects (300–399), e.g. 301 Moved Permanently
  • Client errors (400–499) e.g. 404 Not Found
  • Server errors (500–599) e.g. 500 Internal Server Error

A complete list of HTTP status codes can be found at Mozilla

Typically, you want to decide on which status codes that you want to use and stick to those when sending responses from your API. Usually, not all HTTP status codes are used. In some cases maybe you can get by with only using 200 OK, 404 Not Found and 500 Internal Server Error. What status code that you choose to implement is up to you, but make sure that:

  • They are used to indicate the same status across your API
  • They are properly documented
  • They are used according to their description, e.g. a status code in the 500-599 range should indicate that an error happened

If you implement status code properly in your API, client developers will have an easier time determining what happened when they received a response from your API.

Response Headers

Response headers can be used to embed metadata about the response from your API. A common thing to embed in the metadata of a response is the ID of the API request that was responded to. This could be used for debugging purposes for example.

A header that holds the request ID could look something like:

X-Request-ID: 123e4567-e89b-12d3-a456-426614174000

If a request goes wrong, this can be used to find the correct logs and debug the issue.

There are many different uses for response headers

Versioning

Sooner or later, your API will have breaking changes. To avoid having to ask all of your clients to stop using a deprecated feature, you need to use API versioning. This is typically done using one of the below methods.

URL Based Versioning

Using this method, the different versions of your API live under different URLs. For example:

v1 is accessed on https://yourapi.com/v1

v2 is accessed on https://yourapi.com/v2

This method is quite easy for client developers to implement and is used by giants such as GitHub and Twitter.

Header Based Versioning

Another way for the client to decide which version of your API to use is to include a header. For example, if I send a request with the following header set:

X-Api-Version: v1

The API will use the v1 version.

If I send a request with the following header:

X-Api-Version: v2

The API will use the v2 version.

Whatever method you prefer, API versioning is a must for any serious API developer. It is very hard to handle breaking changes once they are used by different clients.

Consistency Is Key

The key takeaway from this guide is consistency. No matter if we are talking about response codes, naming conventions or versioning the most important factor is that you implement them consistently across all of your API endpoints. This will make client developers happy and help them build amazing solutions on top of your API.


Roy M is a technical content writer for the last 8 years with vast knowledge in digital marketing, wireframe and graphics designing.

Leave a Reply

Your email address will not be published. Required fields are marked *