REST endpoints: verb or noun?

Bruna Pereira
3 min readAug 4, 2020

Versão em português aqui.

This discussion arises from time to time in my daily life. Different people, different points of view, that make us go through different paths to always answer the same question.

The answer does not usually change: it depends.

In the case of less complex cases, where we are applying the concepts of REST to a CRUD, there will rarely be times when we need an endpoint that contains a verb.
When we have applications with more complex behaviors, then this type of questioning arises.

Definitions

Verb: Class of words that, from a semantic point of view, contains the notions of action, process or state.
Noun: Word that names a class of things, people, animals, etc.

We feel very tempted to express endpoints with a verb, because when we call an endpoint, we do want to perform an action. However, for REST services, the verbs are always explicit: they are GET, POST, PUT, etc.

Examples

Case 1:
I have a service that creates contracts related to a specific user. I could create something like:

POST /users/{user_id}/attach-contract

However, the relationship between users and contracts in my domain is very clear:
* A user has multiple contracts.
* A contract always belongs to a user.

Following restful standards I would then have:

POST /users/{user_id}/contracts

Although it is not explicitly written that a contract is being assigned to a user, it is quite clear to people who are used to the REST standard what the endpoint does.

Case 2:
The requirement now is to approve a contract. All contracts have a status and what we want is to assign the approved status.

According to the REST standards and remembering the CRUD model, in the same way that we have a POST, we can also have a PUT and thus just change the state field.

But I don’t want to make all fields available for editing, because all fields are immutable.

In this scenario, it is also tempting to create an endpoint as follows:

POST /users/{user_id}/contracts/{contract_id}/approve

It is also not very scalable to have such an endpoint, because the tendency is for us to have more states, such as: reject, request_change, etc… and for each change, I would have a different endpoint.

Instead, we can define the URL of the status sub-resource, and update through it. Look:

PUT /users/{user_id}/contracts/{contract_id}/status

Avoiding the use of the verb here guides us to a solution that is more flexible and helps in extending the code.

Case 3:
The requirement is that every day at 6 pm, a PDF file of all existing contracts is generated and saved in a file bucket.

There is an external server that takes care of recurring tasks, and our application needs to provide an endpoint for the creation of these contracts.

In this scenario, there is no specific resource that needs to be created or modified within our domain, but it is still an action that needs to be done. Here I would opt for a verb that would better describe what the endpoint does:

POST /contracts/generate-files

Conclusion

It is not completely wrong to use verbs in your endpoints, but you probably don’t need them.
The advantage is basically using the convention and making your API more intuitive for those who are integrating.
Also, note that when using a verb, it is necessary to create a term that is not always related to the domain, adding a cognitive load that is not necessary.
In case 1, for example, for me to describe the behavior of that endpoint I say: create a contract for user X. I don’t need to say create a contract and associate it with user X.
Sometimes it will be necessary, or more appropriate, to represent your endpoints with verbs, but make that decision consciously.

--

--