While REST defines useful constraints, there are still plenty of way to shoot yourself in the foot. Let’s consider an use-case and attempt to write a REST endpoint for it. We’ll strawman some bad designs in order to get to a final good one.
Let’s say we are tasked to implement an endpoint that allows users to delete their accounts. However, due to some manual business processes, user accounts cannot be deleted immediately. The actual business process is:
We are only designing an endpoint for step 1.
One of the design principles of REST is to use the HTTP semantics, so let’s just use the DELETE
method!
Unfortunately, this design is for an endpoint to delete the user, whereas we want to request a deactivation. This would be a suitable endpoint design when we are actually ready to delete the user after the deactivation process has been completed.
Further, if this endpoint did exist and but the user account has not been deactivated yet, it should error with:
OK fine. Let’s add a state
field on the user and let it be an enum of active
, deactivating
or deactivated
. Then we can PATCH
the state
to be deactivating
.
This is better, but this design ends up making the user resource a god object, in which we keep adding new features to a single resource. It would be more maintainable if features could be added more independently.
God objects also tend to bloat the GET
of a resource or worst leak sensitive information if public & private data are stored in the same place.
The ability to PATCH
the state
also implies a user could change their state
back to active
. A guard would need to be implemented to prevent a user from updating their state after the deactivation process has begun, as that would otherwise violate the business process.
Lastly, this API style is passive. The mental model here is by updating the state, some other process will detect/query for update.
Fine! Let’s make write an active command to simply deactivate the user.
This is again better, but semantically this means “deactivate now”. Only a small tweak to get to the final solution.
This may seem like a pedantic distinction, but this is why naming things is hard. Human languages are imprecise and we need to put in extra effort naming things. A good name is the first step towards understanding and ensuring the intended functionality is maintained.
Holup, but isn’t POST
only for creating new resources in REST? REST tells us to write semantic HTTP, so let’s see what the HTTP spec says about POST
.
POST: Perform resource-specific processing on the request payload.
POST
can be used to submit commands to resources.
Do you want write semantic HTTP? You’re in luck, Battlefy is hiring.