CodamAIDocs
Topicdone

Changing with PATCH

PATCH only changes what you name. This page explains the three states of every field (missing, null, value) for simple fields, references and lists.

Variants
field missing → unchangedfield null → clearedvalue → setlist [] → clearedpartial list → target statechild with id → change only what was sentchild without id → createdwithout id → 400

What this is about

With PATCH {basis}/update/{id} you change part of an object. You send only the fields that should change. Everything else stays as it is.

Change only the email
Request
PATCH /api/rest/crm/customer/update/5a2b…
{
  "data": { "id": "5a2b…", "email": "neu@muster.de" },
  "response": ["+"]
}
Response
{
  "data": {
    "id": "5a2b…",
    "_createdOn": "2026-03-02 09:14:00",
    "_updatedOn": "2026-09-21 10:25:07",
    "name": "Muster GmbH",
    "email": "neu@muster.de",
    "phone": "+49 611 123456",
    "note": "Stammkunde"
  },
  "meta": { "error": false }
}

name, phone and note are missing in the PATCH, so they are kept. The response is 200. As with every write, response is required.

How CDMS tells “missing” from “null”

With PATCH, CDMS does not read data into a fixed object with all fields. It reads it as a simple list of keys and values. Then it goes through the fields of the model and asks for each one:

A field in the PATCH
  1. 1
    CDMS
    Is the key in data?
  2. 2
    CDMS
    no → the field is skipped, not changed, not checked
  3. 3
    CDMS
    yes, with null → the field is cleared
  4. 4
    CDMS
    yes, with a value → the value is converted to the field type, checked and set

CDMS ignores keys that the model does not know. Values come in the usual JSON way: a date as "2026-09-21", a timestamp as "2026-09-21 10:25:07", an enum as the name of the value.

The matrix: field kind × state

What PATCH does with a field
Simple fieldSingle referenceList
Key is missingunchangedunchangedunchanged
Value is nullis clearedis detached; a dependent child is deletedall members removed, exactly like []
Value is setis setpoints to the named objectbecomes exactly this list (target state)

So for lists, the target state applies in PATCH too: if you name a list, you name all of it. You cannot add single entries without naming the others. See Lists as target state.

Before, payload, after

A contact with a first name, a last name, a main phone (dependent child) and two more phones (dependent children in a list).

Fieldbeforein the PATCHafter
firstname“Daniel”missing“Daniel”
lastname“X”"Mertins"“Mertins”
birthday1980-04-01nullnull
mainPhonePhone P1missingPhone P1
phonesP2, P3[{ "id": P2, "number": "0611-17277000" }]only P2, with the new number; P3 is deleted
The PATCH for the table
Request
PATCH /api/rest/crm/contact/update/c052…
{
  "data": {
    "id": "c052…",
    "lastname": "Mertins",
    "birthday": null,
    "phones": [
      { "id": "p2…", "number": "0611-17277000" }
    ]
  },
  "response": ["+", { "field": "phones", "response": ["+"] }]
}

Child objects in a PATCH

A child in the PATCH

When: You name an existing child, e.g. in a list or as a single reference.

  1. 1
    Client→CDMS
    sends "mainPhone": { "id": "p1…", "lastContact": null }
  2. 2
    CDMS→Database
    looks up the object p1…
  3. 3
    CDMS→Client
    does not exist → 404 missing-object-for-field|p1…|mainPhone
  4. 4
    CDMS
    exists → the child is handled with PATCH rules as well: only lastContact is cleared, number stays

Result: For the child, only what you name changes. { "id": "p1…" } alone changes nothing on the child. If the relation does not allow changing the children (flag UPDATE missing), the child is only linked and its fields stay untouched, as a single reference and in a list alike.

When: You want to create a new child.

  1. 1
    Client→CDMS
    sends "phones": [{ "id": "p2…" }, { "number": "0611-555" }]
  2. 2
    CDMS
    does the relation allow creating (flag CREATE)? → creates the new phone, with default values and CREATE rules
  3. 3
    CDMS→Client
    without the flag CREATE → 400 recursive-create-not-allowed|phones, nothing is saved
  4. 4
    CDMS
    removes all phones that are not in the list

Result: With the flag CREATE, there are exactly two phones afterwards: P2 and the new one.

When: You want to detach a reference.

  1. 1
    Client→CDMS
    sends "mainPhone": null
  2. 2
    CDMS
    dependent child? → is deleted, with its DELETE hooks
  3. 3
    CDMS
    otherwise → only the link is detached

Result: mainPhone is empty. Whether the phone still exists is defined by the relation.

When a relation is allowed to create or change at all is described in The four cases in nested writing.

The flow

The stations are the same as for PUT: visibility (404), role to change (403), transfer fields, before hooks, validation (422), save, read back. There are two differences:

  • First, CDMS checks whether data has an id key at all. If it is missing, you get 400 missing-id right away.
  • Validation only sees the fields you sent. A required field that you do not send is not checked. A required field that you set to null returns 422 cannot-be-null.

Decision table

Response to PATCH /crm/contact/update/{id}
id in dataobject visiblerole to changesent fields validResponse
no–––400 missing-id
yesno––404 not-found
yesyesno–403 missing-permission|<rolle>
yesyesyesno422 validation-failed
yesyesyesyes200, only the named fields are changed

As with PUT, the id in data counts, not the one in the path. _updatedOn is set to now. Fields starting with _ and fields with the rule @noUpdate stay unchanged.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-generator – ApiProcessor (patchJson, PATCH /update/{id}, /update/{id}/upload)
  • CDMS/cdms-rest-api – AbstractRestApi.patchObject (missing-id), payloads/PatchPayload (HashMap data)
  • CDMS/cdms-system-layer – AbstractSystemLayer.patchObject; AbstractLayer.recursivePatch (containsKey, convertBaseValue), detachOrDeleteModel, reduceToTargetState
  • CDMS/cdms-integrationtest – AbstractRecursivePatch, AbstractPatchTest, AbstractPatchListRecursionTest, ChangeTimestampTest
  • documentation/05-api-guide/06-schreiben.md, 20-api/04-schreibsemantik.md
Search