PUT replaces the entire resource at the target URL (or creates it if absent). Repeating the same request leaves the same final state, so it is idempotent.
PUT sends the full representation of the resource. Sending only some fields may drop the rest, so use PATCH for partial updates. If the target does not exist, respond 201 Created; if you replace an existing one, respond 200 or an empty 204 No Content.
To prevent concurrent-edit lost updates, use a conditional request with `If-Match: <ETag>`. If the ETag no longer matches, the server rejects with 412 Precondition Failed, avoiding overwriting someone else's change.
PUT /api/users/42 HTTP/1.1
Host: api.example.com
Content-Type: application/json
{ "id": 42, "name": "Ada Lovelace" }HTTP/1.1 200 OK
Content-Type: application/json
{ "id": 42, "name": "Ada Lovelace" }curl -X PUT https://api.example.com/api/users/42 \
-H 'Content-Type: application/json' \
-d '{"id":42,"name":"Ada Lovelace"}'await fetch('/api/users/42', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(fullUser)
});