Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

REST API design of a resource whose properties are not editable by the client

Tags:

rest

http

api

What's the best way to handle resource properties which must be modified/updated through another method that is not exposed to the API consumer?

Examples:

  1. Requesting a new token to used for X. The token must be generated following a specific set of business rules/logic.

  2. Requesting/refreshing the exchange rate of a currency after the old rate expires. The rate is for informational purposes and will be used in subsequent transactions.

Note that in the above two examples, the values are properties of a resource and not separate resources on their owns.

What's the best way to handle these types of scenarios and other scenarios where the API consumer doesn't have control of the value of the property, but needs to request a new one. One option would be to allow a PATCH with that specific property in the request body but not actually update the property to the value specified, instead, run the necessary logic to update the property and return the updated resource.

Lets look at #1 in more detail:

Request:

GET /User/1

Response:

{
   "Id": 1,
   "Email": "[email protected]",
   "SpecialToken": "12345689"
}

As the consumer of the API, I want to be able to request a new SpecialToken, but the business rules to generate the token are not visible to me.

How do I tell the API that I need a new/refreshed SpecialToken with in the REST paradigm?

One thought would be to do:

Request:

PATCH /User/1
{
   "SpecialToken": null
}

The server would see this request and know that it needs to refresh the token. The backend will update the SpecialToken with a specific algorithm and return the updated resource:

Response:

{
   "Id": 1,
   "Email": "[email protected]",
   "SpecialToken": "99999999"
}

This example can be extended to example #2 where SpecialToken is an exchange rate on resource CurrencyTrade. ExchangeRate is a read only value that the consumer of the API can't change directly, but can request for it to be changed/refreshed:

Request:

GET /CurrencyTrade/1

Response:

{
   "Id": 1,
   "PropertyOne": "Value1",
   "PropertyTwo": "Value2",
   "ExchangeRate":  1.2
}

Someone consuming the API would need a way to request a new ExchangeRate, but they don't have control of what the value will be, it's strictly a read only property.

like image 795
Omar Avatar asked Feb 15 '23 18:02

Omar


2 Answers

You're really dealing with two different representations of the resource: one for what the client can send via POST / PUT, and one for what the server can return. You are not dealing with the resource itself.

What are the requirements for being able to update a token? What is the token for? Can a token be calculated from the other values in User? This may just be an example, but context will drive how you end up building the system.

Unless there were a requirement which prohibited it, I would probably implement the token generation scenario by "touching" the resource representation using a PUT. Presumably the client can't update the Id field, so it would not be defined in the client's representation.

Request

PUT /User/1 HTTP/1.1
Content-Type: application/vnd.example.api.client+json

{
   "Email": "[email protected]"
}

Response

200 OK
Content-Type: application/vnd.example.api.server+json

{
   "Id": 1,
   "Email": "[email protected]",
   "SpecialToken": "99999999"
}

From the client's perspective, Email is the only field which is mutable, so this represents the complete representation of the resource when the client sends a message to the server. Since the server's response contains additional, immutable information, it's really sending a different representation of the same resource. (What's confusing is that, in the real world, you don't usually see the media type spelled out so clearly... it's often wrapped in something vague like application/json).

For your exchange rate example, I don't understand why the client would have to tell the server that the exchange rate was stale. If the client knew more about the freshness of the exchange rate than the server did, and the server is serving up the value, it's not a very good service. :) But again, in a scenario like this, I'd "touch" the resource like I did with the User scenario.

like image 84
Jonathan W Avatar answered May 12 '23 08:05

Jonathan W


There are many approaches to that. I'd say the best one is probably to have a /User/1/SpecialToken resource, that gives a 202 Accepted with a message explaining that the resource can't be deleted completely and will be refreshed whenever someone tries to. Then you can do that with a DELETE, with a PUT that replaces it with a null value, and even with a PATCH directly to SpecialToken or to the attribute of User. Despite what someone else mentioned, there's nothing wrong with keeping the SpecialToken value in the User resource. The client won't have to do two requests.

The approach suggested by @AndyDennie, a POST to a TokenRefresher resource, is also fine, but I'd prefer the other approach because it feels less like a customized behavior. Once it's clear in your documentation that this resource can't be deleted and the server simply refreshes it, the client knows that he can delete or set it to null with any standardized action in order to refresh it.

Keep in mind that in a real RESTful API, the hypermedia representation of user would just have a link labeled "refresh token", with whatever operation is done, and the semantics of the URI wouldn't matter much.

like image 39
Pedro Werneck Avatar answered May 12 '23 08:05

Pedro Werneck