API design for non CRUD operation

A user resource has properties name, status, and so many other fields. A user can update his name and status.

In typical rest design, a name update could be

patch
/users/123
{
name:“John”
}

Likewise, the status update is also a patch request.
patch
/users/123
{
status:“active”
}

These 2 operations can have a single route /users/123 and its implementation could be in an update action of UserController.
But if I want to send an email before changing the status, we can’t use a single action for both of these operations.
In that case, do I need to have separate routes for both of these actions? If so what should it look like?

I cannot follow to be honest. How does sending an email before changing the status affect if API endpoints, which could be used for it? Would be great if you could elaborate a little bit.

I guess the user should not be able to change the status directly. Instead the user creates a request to change the status. This status change request triggers an email to someone in order to approve or reject the request.

That case could be handled by having an additional property requestedStatus. A client would send a PATCH request updating the requestedStatus of a user resource.

PATCH /users/123

{
  "data": {
    "type": "users"
    "id": "123",
    "attributes": {
      "requestedStatus": "active"
    }
  }
}

An action in the email mentioned above would trigger the following network request:

PATCH /users/123

{
  "data": {
    "type": "users"
    "id": "123",
    "attributes": {
      "requestedStatus": null,
      "status": "active"
    }
  }
}

Very likely you want to implement validation and authorization to expose that functionality only to some clients. E.g. you may have an auth token in that email, which is required to update the status. And you may have a validation, which prevents setting status to another value than requestedStatus for a user.

Thank you for the response.

Let me clarify my requirement. I have 2 operations

  1. Update name (Imagine a user profile update)
  2. Status update (Imagine an admin changes the status of the user)

Both of these operations are patch operations but should be exposed to 2 different user roles. 1st one is for normal users and 2nd other is for admin users.

Since these are patch requests on the same resource we could use the route /users/123

But we have 2 different business logic for these 2 operations. ie We have to send an email to the admin user before changing the status. For profile updates, we don’t need to send the mail.

My question was since it is a single route that is mapped to UserController’s update function, how do I differentiate both of these operations?

From your answer, it is understood that we could use an additional parameter in the request body to differentiate these operations. That means we have to examine the request body and determine what operation is should be carried out.

In this case requestedStatus can be checked. But consider the situation where requestedStatus is used in other update operations, in that case, we need another parameter, right? If there are other kinds of user updates this code will become messy right? Imagine we have 100+ parameters to update. Is this the right way of doing it?

So these actions can be differentiated based on the field “”

1 Like

I don’t know which framework you are using to implement it. But you should be able to get a list of attributes, which are included in the JSON:API document payload and have conditional logic based on that.

1 Like