I'm working with a RESTful API where a POST operation is used to create a user. A required field, which could be an email or a unique user nickname, is unique across the system. The response to this POST contains a unique id for the user, which is a deterministic hash calculated from this unique field. Therefore, the same unique field will always produce the same id, preserving their one-to-one relationship.
Given this structure, there's an inherent challenge regarding the use of the PUT operation. Traditionally, PUT can replace a resource or create a new one if it doesn't exist. However, in this context, the deterministic and immutable relationship between the id and the unique field seems to complicate the semantics of PUT.
My concerns are:
- Given the deterministic nature of the id from immutable properties, is it a good design choice to implement a PUT method for such resources?
 - If the semantics of PUT are challenged by this design, are there any best practices or potential pitfalls that I should be aware of?
 
3 Answers 3
If I understand correctly, you are planning to have a resource along the lines of:
https://yourdomain.com/user
Which supports a POST operation which will return a new resource maybe like:
https://yourdomain.com/user/somesortofhash
There's nothing particularly unusual or difficult allowing PUT to be used on resources created with POST. You can even restrict the ability for the PUT to create a new resource by failing the operation.
The only requirement of PUT is that it needs to be idempotent meaning that if you call PUT successfully multiple times with the same input, the resulting state of the resource will be the same. This is a useful feature because if you have some sort of e.g.: network failure, you can simply retry the PUT call.
What PUT requires in this case is that the called know the id of the user. It is probably a bad idea to have clients calculating the hash for the id themselves as discussed in the comments. Primarily because it would lock you into the hashing routine. In the future you might want to use a UUID instead or perhaps you need to modify the hashing routine because you have had collisions. It really is best to not expose that detail to the client and I take it that you don't want to do that anyway. This doesn't preclude the use of PUT, however.
I think your question may come down to how does the client get that id? First of all, if you return the URI for the user resource from the POST, that's one way. In some circumstances that might even be enough. It's typical though for a REST API to provide a way to look up such resource URIs based on information that they have.
One thing to consider with PUT is that it has complete replacement semantics. This is simple to use but you can run into issues such as dirty reads/writes if you have multiple clients attempting to modify the same resources at the same time. For this reason PATCH is sometimes used to allow clients to update part of a resource without replacing it entirely.
- 
 I appreciate your answer. However, I still haven't received a clarification on a situation where the
id(lets say UUID) is calculated by the server from (for example) anemail. So, in order to allowPUT /users/someexistingidI would require the API user to also provide anemailin the body and is exaclty mapped 1-to-1 withsomeexistingid. The problem is thatidis deterministic and based onemail. And there's only one situation when the user will not have a problem: when he passesidandemaillike he has received them from the server. Withoutemailoperation is impossible.Sergey Kolesnik– Sergey Kolesnik2023年08月17日 19:54:16 +00:00Commented Aug 17, 2023 at 19:54 - 
 "I would require the API user to also provide an email in the body and is exaclty mapped 1-to-1 with someexistingid" The
idwould be in thePUTURI. When thePOSTcreates a new resource, it determines the id based on whatever server-side logic you need and creates a child resource. Does that help?JimmyJames– JimmyJames2023年08月17日 21:44:05 +00:00Commented Aug 17, 2023 at 21:44 - 
 so you have
idintPUTURI. And haveemailin the body, which does not correspond to anidthat would be generated by the server. What then? Erroremail is invalid? Or return a newidthat corresponds to the newemail(makes no sense forPUT)?Sergey Kolesnik– Sergey Kolesnik2023年08月17日 22:35:57 +00:00Commented Aug 17, 2023 at 22:35 - 
 1@SergeyKolesnik, if the 1-to-1 logic of email to id needs to remain true for the lifetime of the resource, then a PUT request with a change to the email should get an error response, because it would put the resource in an internally inconsistent state. What the clients need to know is which attributes/fields should be considered to be read-only.Bart van Ingen Schenau– Bart van Ingen Schenau2023年08月18日 09:43:17 +00:00Commented Aug 18, 2023 at 9:43
 - 
 @SergeyKolesnik I see. You could throw an error as Bart notes. You might also consider dispensing with ids derived from data fields and use something like a UUID instead.JimmyJames– JimmyJames2023年08月18日 14:35:04 +00:00Commented Aug 18, 2023 at 14:35
 
Three variations of PUT:
You accept the representation of the resource provided in the request as is, and keep the URI unchanged. This is the primary interaction that PUT was designed for.
You use the information in the request to recalculate the representation of the resource yourself, and keep the URI unchanged. Not quite so easy - we need to be a little bit careful with things like Validation headers, see RFC 9110.
If you need to try to change the URI... that's where the dragons lurk in the hungriest dark.
In the case where you expect clients to be bespoke implementations designed to interface specifically with your API, you probably don't have much of a problem - you tell the client implementers how to identify the new URI to be used, and get on with your life.
But if people are connecting to your API using general purpose components (like a web browser), then communicating the URI change to the client gets a little bit spooky. The closest real thing you have are redirects, but automatic redirection may cross you up (especially since for some redirect messages clients have a bit too much freedom about which message they use).
Being concerned here is good, and you should investigate carefully to make sure that you understand the tradeoffs involved, and whether "clever" is really the right answer (in both short and long term).
I would just return a well-described 400 Bad request or 409 Conflict in case the unique field is changed. And/or only accept PATCHes that don't include that field.
- 
 Or just "never make id dependable in the first place"Sergey Kolesnik– Sergey Kolesnik2023年08月18日 10:01:02 +00:00Commented Aug 18, 2023 at 10:01
 
idis calculated from (possibly immutable) fields by an internal algorithm, which the API user is not supposed to know of. I don't think he is also supposed to know which feilds are used. So I don't feel comfortable requesting the user to provide a field (set of fields) with "exactly the same value". Such reuiqrement would be unfulfillable in such cases when the caller has a permission toreplacean existing user, but is not allowed to know the personal details due to privacy reasons.