REST API - Best Practices

In the world of programming, consistency is one of the core principles allowing code to be readable. Consistency is often enforced through conventions, or more gently put, “best practices”.

Resources

At the highest level, the purpose of an API is to enable interaction between two or more applications.

This means that an API’s role is to allow the exchange of information, which is why web servers are commonly referred to as APIs - their main purpose is to expose endpoints for the consumption of other applications, _and yes, your browser also fits the role as an application, so even static websites aren’t exempt from this).

The aforementioned exchange of information can be broken down in resources, which are the “things” that you want to exchange with other applications, to put it bluntly.

Here’s a few examples: - users - articles - comments

Your APIs must leverage these resources, and the rest of this article will explain how.

Actions

It’s very easy to swept by programming standards telling you to create functions like getUser(id), createUser(id, name), deleteUser(id) or getUsers() and apply those same standards to a REST API.

You might be tempted to use endpoints like those:

/createUser
/getUsers
/getUser?id=1
/updateUser?id=1&name=janedoe
/deleteUser?id=1

But when it comes to making an API, while it may appear perfectly fine, it isn’t.

HTTP has something specifically to make your life much easier and I’m sure you’ve heard of at least two of them before: GET, POST, PUT and DELETE.

They’re called HTTP methods, sometimes referred to as verbs: - POST is for creating a resource - GET is for reading a resource - PUT is for updating a resource - DELETE is for deleting a resource

Instead of using different names for the manipulation of a single resource, it’s significantly easier for developers to navigate your API if all your endpoints are consistent, and you really can’t get more consistent than using the exact same path but with different methods to differentiate each actions.

Using the name of the resource as endpoint will prevent other developers from wasting their time wondering if you used /addUser, /createUser, /register or even /registerUser as endpoint.

Instead, it’ll just be:

POST   /users
GET    /users
GET    /users/1
PUT    /users/1
DELETE /users/1

Here’s a table to summarize:

Path / Method GET POST PUT DELETE
/users Retrieve a list of all users Create a user Delete all users
/users/1 Retrieve user 1 Update user 1 Delete user 1
/users/1/books Retrieve user books Create user book Delete all of user 1’s books

URL

The resources exposed in your API should use the plural form (e.g. users instead of user)

Ignoring query string values, your URL must be all lowercase.

If one of your resources has multiple words, each word must be separated by a hyphen (e.g. private-messages).

API versioning

Finally, API versioning, although often overlooked, is key to creating an API that will withstand the test of time.

As grandiose as that sounds, it’s as simple as prefixing your endpoints with the current version of your API.

For instance, instead of using /api/users/1, you’d use /api/v1/users. This is especially useful when your API is used by others, since it allows you to make breaking changes to your API without the consumers of your API being affected (both /api/v1/users and /api/v2/users would be available at the same time, thus allowing some time for your API’s consumers to migrate to the new version).

Obviously, versioning is not always a necessity. If your API has no consumers outside of yourself, there’s no good reason to keep old code around. The best example I can think of right now in which API versioning is absolutely necessary is an OAuth2 producer. If we take Google for example, there is an uncountable amount of applications and websites that rely on Google’s Authorization Server (does Sign in with Google ring a bell?). Without API versioning, any breaking change made to the API would affect all those applications.