A bug I see in nearly every web app: If someone saves a stale record, it...
A bug I see in nearly every web app: If someone saves a stale record, it overwrites the newer DB record. 😬
Solution:
1. Provide 'updated' time with each GET
2. Require 'updated' when sending a POST/PUT
3. If 'updated' doesn't match the DB, return an HTTP 409 (conflict)

When the API returns an error status because the record was stale, tell the user "The record you tried to save has been changed by someone else."
Then, 4 options:
1. Tell the user to reload and try again (Easiest and safest, but annoying for the user)
2. Provide a "Save anyway" button (Risky. I don't recommend it)
3. Provide a diff view so they can resolve the conflict (likely overkill, but worth considering for tech saavy users)
4. Use a websocket to notify the user the moment the record they're viewing is updated in the DB by someone else (friendliest, because the user finds out immediately when they're editing stale data. The user can copy their changes and reload to avoid losing work).
I prefer 4, but 1 is most practical in systems where conflicts are rare.
If you prefer, etags can solve this problem, and also have the benefit of potentially saving some bandwidth via caching.
But, I find the etag spec clunkier to implement and work with.
More on etags: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
Oops! I made a typo in the initial tweet. I meant to say "PUT" in step 2. Corrected text and image:
Solution: 1. Provide 'updated' time with each GET
2. Require 'updated' when sending a PUT
3. If 'updated' doesn't match the DB, return an HTTP 409 (conflict)

Clarification: The PUT call merely sends the 'updated' field (received via the GET) back in the PUT request. It doesn't change it.
This way, the PUT call can read the 'updated' field and reject the call if it doesn't match the DB's current 'updated' value.