Is it recommended practice to implement the below endpoint using 'PUT' verb to create & update a resource?
PUT/jobs/{jobid}
(or)
- POST/jobs - to create resource
- PUT/jobs/{jobid} - only to update the existing record
Mixing up create & update logic in PUT endpoint may create issue in the endpoint consumer side as PUT is idempotent while POST is NOT idempotent.
What are the other consequences if I mix up create & update resource logic with in 'PUT' endpoint?
Point me to any relevant RFCs, if any.
CodePudding user response:
The HTTP PUT verb is used to update a resource, but it can also be used to create a resource if the resource does not already exist, but it's bad practise as it goes against its meaning.
POST is not idempotent, while PUT is idempotent. This means that multiple identical POST requests may create multiple resources, while multiple identical PUT requests should update the same resource each time.
If you want to support both creating and updating a resource using the same endpoint, you can use the POST verb for both operations and include an additional parameter or field in the request to indicate whether you are creating or updating the resource.
you can refer to the HTTP 1.1 specification (RFC 7231): https://tools.ietf.org/html/rfc7231#section-4.3
CodePudding user response:
Mixing up create & update logic in PUT endpoint may create issue in the endpoint consumer side as PUT is idempotent while POST is NOT idempotent.
It shouldn't introduce any client issues.
An important constraint in REST is the uniform interface, which means (among other things) that everybody understands message semantics the same way. In the context of HTTP, that means that everybody agrees that HTTP PUT means... whatever the current standard says it means.
The current registered reference for HTTP PUT is RFC 9110:
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message content.
A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response.
In other words, PUT is a lot like "save file"; it's the HTTP method we would use if we were using HTTP to publish a new page to our website.
The uniform interface constraint tells us that our HTTP APIs should understand messages exactly the same way that a general purpose web server would understand them.
The power that gives us is that it allows us to use general purpose components (browsers, caches, proxies) without needing to know anything about the semantics of the resource or its representation.
(Note: the important thing to recognize is agreeing on what the messages mean doesn't mean that the server needs to do a specific thing. See Fielding 2002 on the semantic constraints of HTTP GET; the principle is general to all standardized HTTP methods).
Now, you can use HTTP POST if you prefer (see Fielding, 2009). The problem is that POST semantics allow a lot more freedom, which restricts a general purpose component from doing intelligent things because it doesn't know enough about what is going on.
For example, on an unreliable network an HTTP response may be delayed or lost. Because the semantics of PUT describe an idempotent action, general purpose clients can know that it is safe to try sending the request again. POST, on the other hand, doesn't imply that constraint, and therefore general purpose components shouldn't automatically retry those requests.
But it's a trade off - POST limits what a general purpose component can do in response to a contingency, but maybe it is worth it if that means your API is more familiar to the human developers who are going to use it, or if it makes life easier for the operators keeping your API running, or whatever.
if PUT can create or update a record then how it should be idempotent?
Because idempotent, in HTTP means:
the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.
It's a lot like how we use maps/dictionaries/associative-arrays to store information
dict["readme.txt"] = "Hello World"
and
dict["readme.txt"] = "Hello World"
dict["readme.txt"] = "Hello World"
dict["readme.txt"] = "Hello World"
Call it once, call it twice, call it thrice, the end result is the same: we have this specific value stored under this specific key.
That's really what PUT means; the target URI is the key, the request body is the value. "Please make your document look like my document".