Skip to main content
Send PUT Requests

Send PUT Requests

PUT replaces an existing resource with the representation in the request body. Repeating the same PUT should leave the resource in the same state, which is why PUT is considered idempotent.

Update a record

const response = await fetch('/api/notes/42', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: JSON.stringify({
    title: 'Updated title',
    body: 'Updated content',
    status: 'published',
  }),
});

if (!response.ok) {
  throw new Error(`Update failed: ${response.status}`);
}

const saved = response.status === 204 ? null : await response.json();

Full representation

Send every field the resource needs, not only the changed one. If a field is omitted, the server may treat it as null or reject the request depending on its rules. PATCH is the method for partial updates.

PUT versus PATCH

  • PUT replaces the resource; the client supplies the complete state.
  • PATCH applies a partial change; the client supplies a diff or a subset.
  • Both can be idempotent, but PATCH depends on the patch format.
await fetch('/api/notes/42', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/merge-patch+json' },
  body: JSON.stringify({ status: 'archived' }),
});

Responses

A successful update returns 200 with the updated representation or 204 with no body. A missing resource returns 404; a validation failure returns 400 or 422; a conflict returns 409. Handle each case explicitly instead of only checking for "not an error".

Optimistic interface updates

You can update the page immediately and roll it back if the request fails. This feels fast, but only when failures are rare and easy to reverse. Keep a copy of the previous state.

const previous = note.title;
note.title = input.value;
render(note);

try {
  await save(note);
} catch (error) {
  note.title = previous;
  render(note);
  showError('Could not save the title.');
}

Concurrency

Two users may edit the same record. Send a version number or an If-Match header so the server can reject a stale write with 409 or 412. Without a version check, the last request silently wins and the other change disappears.

await fetch(`/api/notes/${note.id}`, {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'If-Match': `"${note.version}"`,
  },
  body: JSON.stringify(note),
});