CodamAIDocs
Topicdone

Replacing with PUT

PUT describes the complete target state. This page explains what happens to missing fields, references and lists, and where the ID comes from.

Variants
simple field missing → emptyreference missing → detacheddependent child missing → deletedlist missing → clearedchild with id → linked or replaced along with itchild without id → createdID from data, not from the pathnot visible → 404

What this is about

With PUT {basis}/update/{id} you replace an object. What you send in data is the complete target state: this is how the object should look afterwards, field by field.

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

note was set in the object before, but it is missing in the PUT. That is why it is empty now. The response is 200. As with reading, response decides which fields come back, and it is required.

Before, payload, after

A company with a name, a note, a main address (reference) and two employees (list). The employees are dependent children: they belong to the company and are deleted with it.

Fieldbeforein the PUTafter
companyname“CodamIC”"Codamic AG"“Codamic AG”
note“Stammkunde”missingnull
logo“logo.png”nullnull
mainAddressAddress Amissingdetached, address A still exists
employeesAnna, Ben[{ "id": Anna, …all fields… }]only Anna; Ben is deleted

The table shows the three rules for the three field kinds:

What PUT does with a field
Simple fieldSingle referenceList
Field is missing or nullis clearedis detached; a dependent child is deletedall members are removed
Field has a valueis setpoints to the named object afterwardsbecomes exactly this list (target state)

Whether a reference is only detached or the child is deleted is defined by the relation in the model. See Relation types and recursive flags.

The stations of a PUT

PUT /api/rest/crm/customer/update/5a2b…
  1. CIAS
    Filter chain
    Is the token valid?
    ↳ no 401
  2. CDMS
    Field selection
    Is there a response in the body?
    ↳ no 400 response
  3. CDMS
    Visibility
    Does the object with data.id exist, and may the person see it? Same filters as for reading.
    ↳ no 404 not-found
  4. CDMS
    Model role
    Does the person have the right to change customer? The same applies to every child that is changed along with it.
    ↳ no 403 missing-permission|<rolle>
  5. CDMS
    Transfer fields
    Every field of the model is set to the value from data, missing ones to empty. Rule violations are collected.
  6. Hook
    Before hooks
    Hooks see the changed object and may still adjust it.
  7. CDMS
    Validation
    Are all rules met after the hooks?
    ↳ no 422 validation-failed with all violations
  8. Database
    Save and read back
    Write the change, run after hooks, then read the object again with the response
  9. 200 with the object as it looks now

Two things stand out:

  1. Visibility comes before the role. An object you may not see returns 404, even if you also lack the role to change it. See Why invisible objects return 404.
  2. Reading back is part of the request. It runs with your read permissions, in the same transaction. If it fails, the change is not saved either.

_createdOn stays as it was, _updatedOn is set to now. CDMS skips all fields starting with _ and the id when writing. See System fields that the server sets.

Where the ID comes from

With PUT, the id appears twice in the request: in the path and in data. data.id is what counts. CDMS does not evaluate the path.

The id with PUT /update/{id}
data.idid in the pathWhat happens
presentsamethe object with this id is replaced
presentdifferentthe object from data.id is replaced, without an error
missingany400 missing-id

Child objects in a PUT

You can send references and list entries as objects. What CDMS does with them depends on two questions: Does the child have an id? Does the relation allow creating or changing children?

A child in the PUT

When: The relation does not allow changing the children. Typical for pointers like mainAddress.

  1. 1
    Client→CDMS
    sends "mainAddress": { "id": "a7…" }
  2. 2
    CDMS→Database
    looks up the object a7…
  3. 3
    CDMS→Client
    does not exist → 404 missing-object|a7…|mainAddress
  4. 4
    CDMS
    exists → the reference now points to it; other fields of the child stay untouched

Result: The company points to address a7…. The address itself does not change.

When: The relation allows changing the children. Typical for dependent children like employees.

  1. 1
    Client→CDMS
    sends "employees": [{ "id": "k1…", "firstname": "Anna", "lastname": "Schmidt" }]
  2. 2
    CDMS
    replaces the child k1… with PUT rules as well: missing fields of the child are cleared
  3. 3
    CDMS
    removes all other employees, dependent ones are deleted

Result: Only Anna stays, with exactly these fields. If you send only { "id": "k1…" }, her fields are cleared. For required fields you get 422 employees[0].firstname cannot-be-null.

When: You want to create a new child.

  1. 1
    Client→CDMS
    sends "employees": [{ "firstname": "Cem", "lastname": "Yıldız" }]
  2. 2
    CDMS
    relation allows creating? → creates the employee, with default values and CREATE rules
  3. 3
    CDMS→Client
    not allowed → 400 recursive-create-not-allowed|employees

Result: Cem is created and assigned to the company. All previous employees are removed because they are missing from the list.

The complete rules are in The four cases in nested writing and Lists as target state.

Decision table

Result per field with PUT
Field kindin the PUTRelation: dependent childAfter
simple fieldmissing / null–empty
simple fieldvalue–new value
single referencemissing / nullnodetached, the object still exists
single referencemissing / nullyesthe child is deleted
listmissing / null / []noall links detached
listmissing / null / []yesall children deleted
listpartial list–exactly these members; members not named are detached or deleted

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-generator – ApiProcessor (updateJson, PUT /update/{id}, /update/{id}/upload), RestPayloadProcessor (UpdatePayload, IdWrapperPayload)
  • CDMS/cdms-rest-api – AbstractRestApi.updateObject, payloads/WritePayload, Expander
  • CDMS/cdms-system-layer – AbstractSystemLayer.updateObject; AbstractLayer.recursiveUpdate, setModel, detachOrDeleteModel, reduceToTargetState, assertVisibleForWrite
  • CDMS/cdms-integrationtest – AbstractUpdateTest, AbstractRecursiveUpdate, AbstractManyToManyTest, ChangeTimestampTest
  • documentation/05-api-guide/06-schreiben.md, 20-api/04-schreibsemantik.md
Search