I am developing a REST API in Spring boot and i am trying to understand the PUT action. Currently my PUT action takes the object id and checks if the object is present and then replaced the object with the new one. I have the following questions.
Should i compare the old object with the new one before saving the new one to know if the newobject is modified at all and return an approriate http response status if the object is unchanged ?
If i do want to compare, what is the best way to know if the object is really modified or not
Thanks.
No, you don't need to compare generally. PUT means you need to replace all the values with new ones, but if you need to keep the created by or created time properties you should get the record from db and update necessary values form previous record to new one.
If you need to compare two objects you need to override equal and hashCode method. then you can check a.equal(b) to check whether values are changed. Keep in mind if object contains datatime or random generation numbers avoid adding them inside equal method.
PATCH is where you need to get the current record from db and update relevant values.
You can decide between PUT or PATCH, not all protocol support PATCH.
When a client needs to replace an existing Resource entirely, they can
use PUT. When they’re doing a partial update, they can use HTTP PATCH.
if you are using PUT there you need to do all compare things and check for example:
Get Object from DB
check and update whatever is updated business object
then save.
to answer your question, object is modified is not required you to compare value from existing object and new object.
but if client side OK to send only updated properties then PATCH is better to use.
to know more and how you can implement, please blog
HTTP PUT vs HTTP PATCH in a REST API
REST: Should PUT endpoint compare the GET response before updating?
Neither REST nor HTTP put any particular constraints on the implementation - only the semantics are constrained. RFC 7231
HTTP does not define exactly how a PUT method affects the state of an origin server beyond what can be expressed by the intent of the user agent request and the semantics of the origin server response.... Generally speaking, all implementation details behind the resource interface are intentionally hidden by the server.
RFC 7232 might have a clue to what you are looking for
An origin server MUST NOT perform the requested method if a received If-Match condition evaluates to false; instead, the origin server MUST respond with either a) the 412 (Precondition Failed) status code or b) one of the 2xx (Successful) status codes if the origin server has verified that a state change is being requested and the final state is already reflected in the current state of the target resource (i.e., the change requested by the user agent has already succeeded, but the user agent might not be aware of it, perhaps because the prior response was lost or a compatible change was made by some other user agent).
So as far as the spec is concerned, you can pretend that you changed things, even though a no-op was equivalent to what the client asked for.
If i do want to compare, what is the best way to know if the object is really modified or not
Not enough information provided. That's going to depend on things like how the origin server stores resource state. If you are just dealing with raw documents, then comparing two long hash keys could be fine.
Related
Odata V4 Spec says that Actions MAY have observable side effects and should be invoked using HTTP POST. But we do have scenarios where we need to use actions which just modifies some status.
For example :
1.You might want to mark status of a document identified by a id as locked
Endpoint - .../Documents({id})/lock().
Since I am doing a partial update here, In my opinion PATCH is more suitable.2. You might want to offer two ways of deleting a document
a) Just Hide Endpoint - ...../Documents({id}) This is with HTTP DELETE (no disputes)
b) Delete PermanentlyEndpoint - ...../Documents({id})/permanentDelete() This as an ODATA action. In my opinion, HTTP Delete would be more appropriate here instead of HTTP POST.
What is the recommended way to do this from Odata standpoint? Any help here is much appreciated.
Below is the information from SPEC.
SPEC
11.5.4 Actions
Actions are operations exposed by an OData service that MAY have side effects when invoked. Actions MAY return data but MUST NOT be further composed with additional path segments.
11.5.4.1 Invoking an Action
To invoke an action bound to a resource, the client issues a POST request to an action URL. An action URL may be obtained from a previously returned entity representation or constructed by appending the namespace- or alias-qualified action name to a URL that identifies a resource whose type is the same as, or derives from, the type of the binding parameter of the action. The value for the binding parameter is the value of the resource identified by the URL prior to appending the action name, and any non-binding parameter values are passed in the request body according to the particular format.
Thanks in advance
--ksp
From an OData standpoint, you always have to invoke an action with a POST, with any other verb, it won't work.
Both of your examples are things that I personally don't think are well suited to an action as there are already ways to do these things with OData and they use the verbs that you are mentioning.Updating a property is supported with a PATCH and deleting an object is supported with a DELETE. You mention that you have two different types of delete operations, this is more difficult but you could use a custom header to distinguish between them.
An action tends to be something that doesn't fit into the normal CRUD operations so it isn't always clear which HTTP verb should be used for this.
In your examples, it does feel right to want to use DELETE and PATCH. However, the problem comes because we need to have a standard to follow, bear in mind that OData actions are all discoverable through the metadata so could be consumed by a client with no knowledge of what the actions actually do and in this case, we need to have something defined. Since we know that actions affect the server in some way, to me, it seems like POST is the least bad option that is consistent for all actions.
At the end of the day, as the author, your API is yours to command. Just as we shouldn't use properties in C# class design that cause side affects in other properties, that doesn't mean we cant, and it can be pretty common.
From an OData standpoint, PATCH is analogous to using property accessors and actions or POST is for accessing methods.
Making the decision between PATCH or POST to affect change is therefor the same design decision between using property mutators (making them writable) or forcing the caller to set their values through related methods.
You might want to mark status of a document identified by a id as locked
Endpoint - .../Documents({id})/lock().
Since I am doing a partial update here, In my opinion PATCH is more suitable.
If your resource has a property called Locked, and your current lock() Action only sets the Locked property to true, then you could simply use PATCH to update just that Locked field.
Some common reasons to use an Action specifically for a lock process:
You want to execute specific logic when lock() is called and you want to maintain this logic in it's own method, rather than having complex conditional logic inside your patch handler.
You don't want the reverse logic, unlock() to be available to everyone, when a resource is locked, presumably only the user who locked it can release the lock or other conditions need to be satisfied.
as with the first point, this sort of logic is generally easier to maintain in its own method, and therefore Action.
You want to use Security Attributes to restrict access to lock() to certain security groups, yet you want all users to have read access the the Locked state field.
When a resource is locked other fields are also set, like LockedBy and perhaps DateLocked.
While all of that logic could be managed in your single PATCH endpoint logic for the controller, I can't stress enough how this can easily make your solution unmanageable over time or as the complexity of your resource increases.
More importantly: the documented and accepted convention is that PATCH will NOT have side effects, and as such there is no need to execute a GET after a PATCH because the same change on the client has been accepted on the server. Conversely, because a POST MAY have side effects, it is reasonable for the client to expect to execute a GET to get all the related changes if the response from the POST does not contain the updated resource.
In the case of Delete vs PermanentlyDelete now things become personal / opinionated...
By convention, the expectation of DELETE is two fold:
After a delete the resource should no longer appear in collection query results from a GET
After a delete the resource should no longer appear in item requests via GET
From a server point of view, if my resource has a soft delete, that simply sets a flag, and a permanent delete that deletes the record from the underlying store, then by convention I would use an Action called Delete() for the soft delete, and the permanent delete should use the DELETE http verb.
The general reasoning for this is the same as for the discussion about locked().
However, if the intention of soft vs permanent delete is to intercept the client's standard delete workflow, such that the permanent delete concept is hidden or otherwise abstracted in a way that it is not part of the usual workflow (the user has to go somewhere different, like the recycle bin to view deleted records and restore or permanently delete), in that scenario, use the HTTP verb DELETE for soft delete, and make a specific, perhaps collection bound Action to accept the request for permanent delete
This action may have to be unbound, or bound to the collection depending on how you implement your filtering, if we have deleted record 'xyz' such the GET: ~/document('xyz') returns NOT-FOUND then we can't really expect POST: ~/document('xyz')/delete() to execute...
Several authors say that in the REST architecture, the POST method should be used to create a new resource, and only the PUT method is used to update an existing resource (or create a new one).
But the problem is that the PUT method is idempotent, so if a resource has a date field named "updatedTime" that must be set in the server side for reliability, the updated operation is no longer idempotent (because the value of the "updatedTime" will always change in each new operation), so PUT can not be used, and as POST is used only to create a new object how to fix this?
AS per HTTP's definition of idempotent :
Like the definition of safe, the idempotent property only applies to
what has been requested by the user; a server is free to log each
request separately, retain a revision control history, or implement
other non-idempotent side effects for each idempotent request.
So you're free to modify the updated time in an underlying server object as long as it doesn't affect the resource served by the HTTP server.
If you're concerned about breaking idempotency (although one could debate whether it is a real violation), I would therefore advise you to store updatedTime in a server object field but only expose information about it through an appropriate Last-Modified header instead of putting it in the response body that represents the resource.
As a side note, POST is not only to create resources (see the spec)
Since PUT is idempotent, how handle the situation which with the server add or change informations from the object send by the client ?
If all my resources have 'createdDate' and 'updatedDate' fields, should the client always use PATCH method (and never PUT) if I don't want the client to choose the value of these fields ?
PUT replaces the resource pointed to by the URL.
PATCH modifies the resource pointed to by the URL.
If you are modifying some subset of the properties of a resource, then PATCH is appropriate.
Just because PUT replaces an object in full doesn't mean you have to expose all fields for update. If you want create and updated dates done only on the backend, then do not expose them in either your PUT or PATCH methods.
Your RESTful API does not have to be exactly the same as your persistence/database methods.
From my understanding, if completely following the HTTP spec, if you are doing a PUT command you need to pass in all the data for the resource (whether or not it changes) and when doing a PATCH command you need to only pass in the data that is changing. So if I had a resource in which I was going to change every value of it, the PUT and PATCH command would have the same request except for the HTTP verb being used.
From a backend prospective, I am finding it hard to come up with a viable reason to have different functionality for PUT and PATCH. The REST API I have been building right now supports both methods however they point to the same code and the code really just does a PATCH as it does not request all the data of the resource, just the changed data. I would like to have a really good reason to have to maintain a separate code path for PUT for all my resources as that adds a bit to code maintenance.
Is there any reason to really have different functionality for both PUT and PATCH when the code for PATCH can really do a PUT too (besides you should follow the spec as I don't find that a great reason on its own in this case)?
Is it considered bad practice or acceptable to have both PUT and PATCH accept only a list of changed data of the resource?
Even though both verbs seem quite similar, there are small, mostly semantic differences that should be considered when using one of the verbs.
PUT is idempotent, PATCH is not, which means that the side effects of a sequence of identical PUT-requests are the same as for a single request. This is not true for PATCH, even though it can be forced to be idempotent.
It is possible to use PATCH in a way where you need to know the server-side state of the resource first. This makes collisions more 'dangerous' than PUT-requests, because if you base the operation on a point/state that has already changed in the meantime, you might corrupt the resource. It's on the client's behalf to take care such cases. This is not necessary for simple operations like appending a list item (because the previous state doesn't matter).
Unlike PUT, a PATCH is not of the same entity as the resource it modifies. It only describes some sort of delta, but not a full representation of the resource. Therefore, it is not quite true when you say "...if I had a resource in which I was going to change every value of it, the PUT and PATCH command would have the same request except for the HTTP verb being used". This also means, that a PATCH must not necessarily be of a smaller document size than the whole resource data you would use with PUT.
"It is expected that different patch document formats will be
appropriate for different types of resources and that no single format
will be appropriate for all types of resources. Therefore, there is
no single default patch document format that implementations are
required to support. Servers MUST ensure that a received patch
document is appropriate for the type of [the requested] resource"
- RFC 5789
The comparison between PUT an PATCH is not quite trivial as it may seem, because you also should consider POST, since POST can also be used for partial modification.
Right now, PATCH is just a proposal and has not been completely/officially standardized yet.
So, as you can see, there are some differences between PUT and PATCH. Sometimes it can be important to be able to accurately describe the changes of a resource, so there sure are appropriate use-cases for PATCH. I think it's a good idea to provide both, but be aware that they're not really the same. Use PATCH for realative/partial updates and PUT to update the entire resource.
The difference between PUT and PATCH is that PUT asks the server to completely ignore the current state, while PATCH asks the server to consider the current state before applying the payload.
You think there are no differences because you're using PATCH to update with a partial representation, passing the data that is changing. That's not how it works. PATCH should use a diff format that makes explicit the current state you're applying the change to, and the resulting state.
For instance, in a JSON API you want to update the email parameter with a patch. The current email is myemail#example.com. You shouldn't just send:
{'email': 'mynewemail#example.com'}
You MUST send something like:
{'old_email': 'myemail#example.com', 'new_email': 'mynewemail#example.com'}
The format may be designed by your, or you may adopt an standardized diff format, depending on your needs. There's an RFC proposal for a standard JSON patch format to be used in these cases.
The use case for a PUT is when you need to completely replace something, ignoring completely whatever is in there, if anything. For instance, an user who is updating his profile. No matter what he does, you want to keep the latest version, ignoring whatever existed before.
The use case for a PATCH is when you need to update something, while considering the current state, and only if it still matches the state it had the last time you checked. For instance, you need to flag some user for being behind in his payments, but between the start of the job and the actual request, the user actually paid and his profile was already updated by another client of your API. If you flag his account as unpaid by sending a full representation with a PUT, you'll overwrite the data saying he has already paid. If you update with a PATCH, the request will be applied only if the user still has the unpaid state you've seen before.
To answer your last question, it's not acceptable to do partial updates with PUT. A PUT request is a complete replacement.
I have a RESTful web service which represent processes and activities. Each activity is inside one and only one process.
I would like to represent a "move" operation of activity between the process it is currently in and another process.
I've look at forums and found people suggest to use MOVE operation which is not very standard and other suggest to use PUT but then I'm not sure how to tell the difference between PUT that update and PUT that moves which looks semantically wrong.
Any ideas?
One way might be to represent the move itself as, say, a "transfer" resource (transfer as a noun), and POST a new one:
POST /transfer
With an entity containing:
activity: /activities/4
toProcess: /processes/13
This way, clients are creating new "transfers" which, on the server, handle validating and transferring the activity.
This gives you the ability to add information about the transfer, too. If you wanted to keep a history for auditing, you could add a transferredBy property to the resource, or a transferredOn date.
If using PUTs, you can tell the difference by whether the process of the existing entity matches the new one.
PUT /process1/activity2
process: 2
some_data: and_stuff
To which the logical response (if successful) is
303 See Other
Location: /process2/activity2
Given the available answers I'm not really satisfied with the proposals.
POST is an all purpose method that should be used if none of the other operations fit the bill. The semantics of a payload received are defined by the service/API only and may therefore a solution for one API but not for most ones. It further lacks the property of idempotency which in case of a network issue will leave the client in an uncertainty whether the request received the server and only the response got lost mid way or if the request failed to reach the server at all. A consecutive request might therefore lead to unexpected results or further actions required.
PUT has the semantics of replace the current representation obtainable from the resource (may be empty) with the representation provided in the payload. Servers are free to modify the received representation to a more fitting one or to append or remove further data. PUT may even have side effects on other resources as well, i.e. if a versioning mechanism for a document update is provided. While providing the above-mentioned idempotency property, PUT actually does not fit the semantics of the requested action. This might have serious implications on the interoperability as standard HTTP servers wont be able to server you correctly.
One might use a combination of POST to create the new representation on the new endpoint first and afterwards remove the old one via DELETE. However, this are two separate operations where the first one might fail and if not handled correctly lead to an immediate deletion of the original resource in worst case. There is no real transactional behavior in these set of operations unfortunately.
Instead of using the above mentioned operations I'd suggest to use PATCH. PATCH is a serious of changes calculated by the client necessary to transform a current representation to a desiered one. A server supporting PATCH will have to apply these instructions atomically. Either all of them are applied or none of them at all. PATCH can have side effects and is thus the most suitable fit to perform a move in HTTP currently. To properly use this method, however, a certain media-types should be used. One might orientate on JSON Patch (more reader-friendly) i.e., though this only defines the semantics of operations to modify state of JSON based representations and does not deal with multiple resources AFAIK.