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
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
deactivated. Then we can
state to be
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
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: 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.