docs(rest): clarify PATCH is a shallow top-level merge (nested objects replaced, not deep-merged)#547
docs(rest): clarify PATCH is a shallow top-level merge (nested objects replaced, not deep-merged)#547kriszyp wants to merge 1 commit into
Conversation
…s are replaced, not deep-merged)
There was a problem hiding this comment.
Code Review
This pull request updates the REST API overview documentation to add a warning explaining that PATCH requests perform a shallow merge, meaning nested objects are replaced rather than deep-merged. The reviewer suggested formatting this warning with bullet points and clear examples to improve readability and make the behavior easier for developers to understand.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| ``` | ||
|
|
||
| :::warning | ||
| The merge is **shallow** (top-level only). Preserving "unspecified properties" applies to top-level attributes — if the body includes a nested object, that whole sub-object is **replaced**, not deep-merged, so any nested properties you didn't include are dropped. For example, `PATCH { "settings": { "theme": "dark" } }` against a record whose `settings` is `{ "theme": "light", "notifications": { ... } }` results in `settings` being just `{ "theme": "dark" }` — `notifications` is gone. To update a single nested field, read-modify-write the parent object (or send the full nested object). Dot-path keys (`"settings.theme"`) are stored literally, not interpreted as paths. |
There was a problem hiding this comment.
The warning paragraph is quite dense and contains inline JSON examples, which can be difficult to read and scan quickly. Formatting this with bullet points and clear step-by-step examples will make the shallow merge behavior and its consequences much clearer to developers.
| The merge is **shallow** (top-level only). Preserving "unspecified properties" applies to top-level attributes — if the body includes a nested object, that whole sub-object is **replaced**, not deep-merged, so any nested properties you didn't include are dropped. For example, `PATCH { "settings": { "theme": "dark" } }` against a record whose `settings` is `{ "theme": "light", "notifications": { ... } }` results in `settings` being just `{ "theme": "dark" }` — `notifications` is gone. To update a single nested field, read-modify-write the parent object (or send the full nested object). Dot-path keys (`"settings.theme"`) are stored literally, not interpreted as paths. | |
| The merge is **shallow** (top-level only). Preserving "unspecified properties" applies only to top-level attributes. | |
| If the request body includes a nested object, that entire sub-object is **replaced** rather than deep-merged. Any omitted nested properties will be dropped. | |
| **Example:** | |
| * **Existing record:** {"settings": {"theme": "light", "notifications": {"email": true}}} | |
| * **PATCH request body:** {"settings": {"theme": "dark"}} | |
| * **Resulting record:** {"settings": {"theme": "dark"}} (the "notifications" object is lost) | |
| To update a single nested field, you must either: | |
| 1. Read-modify-write the parent object. | |
| 2. Send the full nested object with the updated values. | |
| Note that dot-path keys (e.g., "settings.theme") are stored literally as keys and are not interpreted as paths. |
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-547 This preview will update automatically when you push new commits. |
What
Adds a warning to the REST PATCH reference clarifying that the merge is shallow (top-level only): a PATCH whose body contains a nested object replaces that whole sub-object rather than deep-merging it, so untouched nested properties are silently dropped.
Why
The current text ("merging only the provided properties... Unspecified properties are preserved") is accurate for top-level attributes but reads as a deep merge. In practice
PATCH { "settings": { "theme": "dark" } }dropssettings.notifications— a silent data-loss footgun, since the request returns 204 with no indication anything was lost. This came up during exploratory QA (qa-explorer): a single nested-field PATCH silently loses sibling nested data on both engines, with no error and no public docs describing the behavior.The behavior itself is consistent (RFC 7386-style top-level merge) — this PR just documents it and points to the safe pattern (read-modify-write the parent, or send the full nested object). Also notes that dot-path keys are stored literally.
— KrAIs (Claude) on Kris's behalf