3 ms·
> In Javascript, there was always a normal, obvious way to handle Patch, which was to leverage null vs. undefined properties in javascript Yeah, no, patch as y
by zepolen 4y ago
> In Javascript, there was always a normal, obvious way to handle Patch, which was to leverage null vs. undefined properties in javascript
Yeah, no, patch as you describe it is not a patch. Given this:
{field: [1,2,3]}
And given that two clients want to each add 4 and 5 respectively to the document, one will overwrite the other, which breaks the very principle of a patch since you end up with either [1,2,3,4] or [1,2,3,5] instead of [1,2,3,4,5] (or [1,2,3,5,4] depending on who was faster).
> I work in an industry of idiots.
Very true.
- biaachmonkie 4y agoThen you'd have to implement a version or hash field on the object and verify it before updating and fail on mis-match and handle the version mis-match error on the client and re-retrieve and update again. GET: {version: 1, field: [1,2,3]} PATCH: {version: 1, field: [1,2,3,4]} # succeeds PATCH: {version: 1, field: [1,2,3,5]} # fails with HTTP 409 response # Client displays some sort of warning that the update failed, GETs the object again and merges the new state from the server with it's state and can retry the update GET: {version: 2, field: [1,2,3,4]} PATCH: {version: 2, field: [1,2,3,4,5]} # succeeds
- zepolen 4y agoSure, though prefer to use If-Unmodified-Since or If-Match as those are standard and caches support them properly. Another issue is how do you support both removing `field` from the document or setting it to null? Sending `field: null` will only work for one of those cases. Likewise the moment you start to do this architecture is the moment you fail to scale. You're putting unnecessary load on your backend by forcing the client to refetch the resource in order to make another update, not to mention the scenario where a lot of clients are trying to add items to field > GETs the object again and merges the new state from the server At some critical point all those clients will start blocking each other as they constantly make PATCHes that fail and reGET only to fail again because another client managed to make their PATCH before them. The problem made worse by network latency and app code. Patches that work with changesets will support a much higher concurrent write load as the concurrency/serialization is done server side, and the changesets will be small rather than the entire value. Under load all the individual requests may take longer to complete they will all ultimately succeed. Concurrency conflicts may still occur but they will be a couple orders of magnitude less frequent. Depending on the type of update, eg. adding items to a list, this is what you want. Removing / updating values otoh may be classed as something you'd prefer to have constraint check via If- headers.
- withinboredom 4y agoThat is a problem with representation and not a real problem. If you have multiple rows in a db, and want to update a row, do you send all rows or describe precisely how to update the rows? No. you send an update and a predicate on which rows to update.
- Merad 4y agoThat's why I tend to prefer using PUT for idempotent updates... at least the semantics are (should be?) a little more clear. But if you really want to avoid users stomping on each other's changes you basically have to implement concurrency checks throughout your whole application.
- zepolen 4y ago> you basically have to implement concurrency checks throughout your whole application What? That sounds like you're not using a real db.
- Merad 4y agoNope, they're very different things. Database transactions protect you against data corruption if two commands try to modify the same row at the same time. Concurrency checks (which are arguably poorly named) prevent changes from being overwritten because someone attempts an update based on stale data. Imagine that you're using an app to manage customer information. For whatever reason you need to update Jane Doe. You pull up her records and start to make the change, but then realize you're late for a meeting. Afterwards, you finish your changes but you notice that someone accidentally entered her name as lowercase ("doe"), so you correct it and save. Cool! Except it isn't cool, because while you were in your meeting she called in to change her name because she got married and is now Jane Smith. You just reverted her back to Jane Doe. If the app included concurrency checks, it would've used something like the SQL Server rowversion column type or the Postgres xmin system column to detect that Jane's data had been modified after you loaded her user record, and you'd have gotten an error prompting you to refresh the page and make your changes again. It's one of those things that happens a lot more often than you might think in the real world, but yet it's rare enough (or not considered a major problem) so that many apps get away with ignoring it entirely.
- zepolen 4y agoThanks for clarifying, so this isn't about concurrency but rather handling updates based on stale data. I think this really should be up to the client to decide what is required, since there will be cases where the 'nonconcurrent' behavior is in fact expected. In terms of HTTP that would be by using the If-Unmodified-Since header, but yes, it requires server side checks although one can be clever and use a common updated field on all resources.