PUT requests and data consistency?

Thought I'd just double check a potential mistake related to PUT requests that I think I spotted in Stephen Grider's React course objectA: {id:1, title:'Harry Potter', pages:50} - User1(top left of image) & User2 fetch objectA - User1 changes objectA.pages from '50' to '60' - User2 waits 10 minutes and then changes objectA.title from 'Harry Potter' to 'Dark Tower' with the data still populating their screen from the 1st fetch As shown in the image below, Stephen says that the problem here is that User2 will fetch objectA with a pages of '60', and that that will leave their local instance of objectA with a pages property of 50 - at odds with the db. But this doesn't feel right as he's using a PUT request which should overwrite the entire object? I'm not wrong in thinking that the problem with a PUT request here is not that the server sends back a response with the wrong pages property, but that old data is included in the PUT request that erases any of User1's previous changes, right?
6 Replies
Rägnar O'ock
Rägnar O'ock16mo ago
it is just that. In a case of concurrent edition like this one, a PATCH request that only change a subset of the data would be more appropriate. (you can also do it with a put request but that would not respect the description of a PUT request)
JWode
JWode16mo ago
Sure, a PATCH fixes the issue by only overwriting the property it intended to change, but I can't see how a PUT request is appropriate at all in scenarios that involve concurrent access, yet it's right there and often is in tutorials? Just found it interesting that it's such a massive bug sitting there in plain sight 🤷‍♂️ Would it just be a case of changing the application flow, say to have each user check (for exampe) an updatedAt field in a db and re-fetch or merge the info server side?
Rägnar O'ock
Rägnar O'ock16mo ago
it's only an issue if you allow concurrent updates, some apps don't and will prompt you to update your data before attempting to make the update (look at git for example)
JWode
JWode16mo ago
Probably just a semantic point, but isn't this distinct from the issue of concurrent updates? (I probably muddied the water by talking of concurrent access, sorry!) The record doesn't have to be updated at the same time for this problem to occur, the 2nd user just has to have stale data - which like you said can be fixed by re-fetching/updating their records, potentially by checking some sort of field (like updatedAt) on the db It might sound like I'm splitting hairs, but I'm just trying to separate the more traditional concurrency problems (transaction locks) from whatever this is so that I can be clear on how to address it. So... - Use PATCH or - Check the db when a request comes in, and update the front end if it's out of date, which seems like a long winded way of doing things. Sound about right?
Rägnar O'ock
Rägnar O'ock16mo ago
yeah thought, PATH could bring the same issue if 2 users edit the same piece of data only partially, something like :
initial state : { title: "i am a title" }
user 1 : add a period at the end of the title
user 2 : add a capital letter at the start of the title
initial state : { title: "i am a title" }
user 1 : add a period at the end of the title
user 2 : add a capital letter at the start of the title
in this case the edit from user 1 would be overridden completely if you simply replace the value of title (basically same issue as before but at the property level rather than the entity level). and this can be mitigated the same way : - only update the relevant part (with some modification merging if needed, git style) - check if the source data is up to date on both sides and bail out if it's not
JWode
JWode16mo ago
"in this case the edit from user 1 would be overridden completely if you simply replace the value of title"
but at that point isn't that the behaviour I'm looking for? I guess the question is if User1 makes the edit to i am a title. do I want User2 to see that change (by checking and updating their data) before they make their own change, adding the capital? I'm not sure if it matters. Ultimately, if I want to change a property, does your previous change on that field have any impact on my desire to change it? I can't think of why the answer would be 'yes', but that's probably a lack of imagination on my part. ------------ Tbh I guess it's best if I always try to keep the users' data up-to-date. Any chance you've seen any resources on methods to do this, or is there no real best practice? I guess the two that spring to mind are: 1) always provide an accessedAt field when users GET data. On further requests compare that to the updatedAt field in the db. If accessedAt < updatedAt, bail on the operation but provide the updated data in the response 2) compare the object for deep equality instead, and do the same