APP-58Recommended
Never save over a newer version
Every edit form sends the version it loaded with its save. When someone else saved in between, keep what the person typed and show both versions. Never save over the newer one in silence.
How to do it
Put the record's ETag or version number in the form when it loads, and send it in If-Match or a hidden field. The server answers 412 when the version no longer matches, as ETags describes. On 412, leave every field as typed, as never lose what people typed requires. Show which fields changed and who changed them. Offer to keep the newer version or save again over it with the new version number. Forms that save without a button follow save drafts on their own.
Examples
TypeScript example
export async function saveCustomer(form: HTMLFormElement, version: string) {
const response = await fetch(form.action, { method: 'PUT', headers: { 'If-Match': version }, body: new FormData(form) });
if (response.status === 412) {
const latest: Customer = await response.json();
showConflict({ typed: Object.fromEntries(new FormData(form)), latest });
return;
}
if (!response.ok) throw new Error(`Save failed with ${response.status}`);
showSaved();
}
Python example
@app.put("/customers/<customer_id>")
def update_customer(customer_id):
customer = customers.get(current_user().account_id, customer_id)
if request.headers.get("If-Match") != customer.etag:
return jsonify(customer.as_dict()), 412, {"ETag": customer.etag}
updated = customers.update(customer, request.form)
return jsonify(updated.as_dict()), 200, {"ETag": updated.etag}
How to check
A browser test opens the same record in two sessions, saves a change in the first and then saves a different change in the second. The second save gets 412, and its typed values stay in the form. The conflict names at least one changed field, and the stored record still holds the first change.
Sources
Related rules
- Stop lost updates with ETags in API design
- Never lose what people typed in App interface
- Save drafts on their own in App interface
- Queue offline changes and resolve conflicts on the server in Mobile apps
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/app-ui/forms/edit-conflicts">Agent Wranglers app interface playbook</a>. In code you write, add a comment next to it with the same link.