CodamAIDocs
Themafertig

Ändern mit PATCH

PATCH ändert nur das Genannte. Hier stehen die drei Zustände jedes Feldes (fehlt, null, Wert) für einfache Felder, Referenzen und Listen.

Ausprägungen
Feld fehlt → unverändertFeld null → geleertWert → gesetztListe [] → geleertTeilliste → ZielzustandKind mit id → nur Gesendetes ändernKind ohne id → angelegtohne id → 400

Worum es geht

Mit PATCH {basis}/update/{id} änderst du ein Objekt teilweise. Du schickst nur die Felder, die sich ändern sollen. Alles andere bleibt, wie es ist.

Nur die E-Mail ändern
Anfrage
PATCH /api/rest/crm/customer/update/5a2b…
{
  "data": { "id": "5a2b…", "email": "neu@muster.de" },
  "response": ["+"]
}
Antwort
{
  "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 und note fehlen im PATCH und bleiben deshalb erhalten. Die Antwort ist 200, response ist wie bei jedem Schreiben Pflicht.

Wie CDMS „fehlt“ und „null“ unterscheidet

Bei PATCH liest CDMS data nicht in ein festes Objekt mit allen Feldern, sondern als einfache Liste von Schlüsseln und Werten. Dann geht es die Felder des Modells durch und fragt für jedes:

Ein Feld im PATCH
  1. 1
    CDMS
    Steht der Schlüssel in data?
  2. 2
    CDMS
    nein → Feld wird übersprungen, nicht geändert, nicht geprüft
  3. 3
    CDMS
    ja, mit null → Feld wird geleert
  4. 4
    CDMS
    ja, mit Wert → Wert wird in den Feldtyp umgewandelt, geprüft und gesetzt

Schlüssel, die das Modell nicht kennt, ignoriert CDMS. Werte kommen wie im JSON üblich: Datum als "2026-09-21", Zeitpunkt als "2026-09-21 10:25:07", Enum als Name des Werts.

Die Matrix: Feldart × Zustand

Was PATCH mit einem Feld macht
Einfaches FeldEinzelreferenzListe
Schlüssel fehltunverändertunverändertunverändert
Wert ist nullwird geleertwird gelöst; ein abhängiges Kind wird gelöschtalle Mitglieder entfernt, genau wie []
Wert ist gesetztwird gesetztzeigt auf das genannte Objektwird genau zu dieser Liste (Zielzustand)

Bei Listen gilt also auch in PATCH der Zielzustand: Nennst du eine Liste, nennst du sie ganz. Einzelne Einträge hinzufügen, ohne die anderen zu nennen, geht nicht. Siehe Listen als Zielzustand.

Vorher, Payload, Nachher

Ein Kontakt mit Vorname, Nachname, Haupttelefon (abhängiges Kind) und zwei weiteren Telefonen (abhängige Kinder in einer Liste).

Feldvorherim PATCHnachher
firstname„Daniel“fehlt„Daniel“
lastname„X“"Mertins"„Mertins“
birthday1980-04-01nullnull
mainPhoneTelefon P1fehltTelefon P1
phonesP2, P3[{ "id": P2, "number": "0611-17277000" }]nur P2, mit neuer Nummer; P3 ist gelöscht
Der PATCH zur Tabelle
Anfrage
PATCH /api/rest/crm/contact/update/c052…
{
  "data": {
    "id": "c052…",
    "lastname": "Mertins",
    "birthday": null,
    "phones": [
      { "id": "p2…", "number": "0611-17277000" }
    ]
  },
  "response": ["+", { "field": "phones", "response": ["+"] }]
}

Kindobjekte in einem PATCH

Ein Kind im PATCH

Wann: Du nennst ein bestehendes Kind, z. B. in einer Liste oder als Einzelreferenz.

  1. 1
    Client→CDMS
    schickt "mainPhone": { "id": "p1…", "lastContact": null }
  2. 2
    CDMS→Database
    sucht das Objekt p1…
  3. 3
    CDMS→Client
    gibt es nicht → 404 missing-object-for-field|p1…|mainPhone
  4. 4
    CDMS
    gibt es → das Kind wird ebenfalls nach PATCH-Regeln behandelt: nur lastContact wird geleert, number bleibt

Ergebnis: Beim Kind ändert sich nur, was du nennst. { "id": "p1…" } allein ändert am Kind nichts. Erlaubt die Beziehung kein Ändern der Kinder (Flag UPDATE fehlt), wird das Kind nur verknüpft und seine Felder bleiben unberührt, als Einzelreferenz wie in einer Liste.

Wann: Du willst ein neues Kind anlegen.

  1. 1
    Client→CDMS
    schickt "phones": [{ "id": "p2…" }, { "number": "0611-555" }]
  2. 2
    CDMS
    erlaubt die Beziehung das Anlegen (Flag CREATE)? → legt das neue Telefon an, mit Defaultwerten und CREATE-Regeln
  3. 3
    CDMS→Client
    ohne Flag CREATE → 400 recursive-create-not-allowed|phones, nichts wird gespeichert
  4. 4
    CDMS
    entfernt alle Telefone, die nicht in der Liste stehen

Ergebnis: Mit Flag CREATE gibt es danach genau zwei Telefone: P2 und das neue.

Wann: Du willst eine Referenz lösen.

  1. 1
    Client→CDMS
    schickt "mainPhone": null
  2. 2
    CDMS
    abhängiges Kind? → wird gelöscht, mit seinen DELETE-Hooks
  3. 3
    CDMS
    sonst → nur die Verknüpfung wird gelöst

Ergebnis: mainPhone ist leer. Ob das Telefon noch existiert, legt die Beziehung fest.

Wann eine Beziehung überhaupt anlegen oder ändern darf, steht unter Die vier Fälle beim verschachtelten Schreiben.

Der Ablauf

Die Stationen sind dieselben wie bei PUT: Sichtbarkeit (404), Änderungsrolle (403), Felder übertragen, Before-Hooks, Validierung (422), Speichern, Zurücklesen. Zwei Unterschiede:

  • Vorher prüft CDMS, ob data überhaupt einen Schlüssel id hat. Fehlt er, kommt sofort 400 missing-id.
  • Die Validierung sieht nur die gesendeten Felder. Ein Pflichtfeld, das du nicht schickst, wird nicht geprüft. Ein Pflichtfeld, das du auf null setzt, liefert 422 cannot-be-null.

Entscheidungstabelle

Antwort auf PATCH /crm/contact/update/{id}
id in dataObjekt sichtbarRolle zum Änderngesendete Felder gültigAntwort
nein–––400 missing-id
janein––404 not-found
jajanein–403 missing-permission|<rolle>
jajajanein422 validation-failed
jajajaja200, nur die genannten Felder sind geändert

Wie bei PUT zählt die id in data, nicht die im Pfad. _updatedOn wird auf jetzt gesetzt, Felder mit _ und Felder mit der Regel @noUpdate bleiben unverändert.

Fallen

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • 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
Suchen