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.
PATCH /api/rest/crm/customer/update/5a2b…
{
"data": { "id": "5a2b…", "email": "neu@muster.de" },
"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 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:
-
1CDMSSteht der Schlüssel in
data? -
2CDMSnein → Feld wird übersprungen, nicht geändert, nicht geprüft
-
3CDMSja, mit
null→ Feld wird geleert -
4CDMSja, 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
| Einfaches Feld | Einzelreferenz | Liste | |
|---|---|---|---|
| Schlüssel fehlt | unverändert | unverändert | unverändert |
| Wert ist null | wird geleert | wird gelöst; ein abhängiges Kind wird gelöscht | alle Mitglieder entfernt, genau wie [] |
| Wert ist gesetzt | wird gesetzt | zeigt auf das genannte Objekt | wird 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).
| Feld | vorher | im PATCH | nachher |
|---|---|---|---|
firstname | „Daniel“ | fehlt | „Daniel“ |
lastname | „X“ | "Mertins" | „Mertins“ |
birthday | 1980-04-01 | null | null |
mainPhone | Telefon P1 | fehlt | Telefon P1 |
phones | P2, P3 | [{ "id": P2, "number": "0611-17277000" }] | nur P2, mit neuer Nummer; P3 ist gelöscht |
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
Wann: Du nennst ein bestehendes Kind, z. B. in einer Liste oder als Einzelreferenz.
-
1Client→CDMSschickt
"mainPhone": { "id": "p1…", "lastContact": null } -
2CDMS→Databasesucht das Objekt
p1… -
3CDMS→Clientgibt es nicht → 404
missing-object-for-field|p1…|mainPhone -
4CDMSgibt es → das Kind wird ebenfalls nach PATCH-Regeln behandelt: nur
lastContactwird geleert,numberbleibt
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.
-
1Client→CDMSschickt
"phones": [{ "id": "p2…" }, { "number": "0611-555" }] -
2CDMSerlaubt die Beziehung das Anlegen (Flag CREATE)? → legt das neue Telefon an, mit Defaultwerten und CREATE-Regeln
-
3CDMS→Clientohne Flag CREATE → 400
recursive-create-not-allowed|phones, nichts wird gespeichert -
4CDMSentfernt 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.
-
1Client→CDMSschickt
"mainPhone": null -
2CDMSabhängiges Kind? → wird gelöscht, mit seinen DELETE-Hooks
-
3CDMSsonst → 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üsselidhat. Fehlt er, kommt sofort 400missing-id. - Die Validierung sieht nur die gesendeten Felder. Ein Pflichtfeld, das du nicht schickst, wird nicht geprüft. Ein Pflichtfeld, das du auf
nullsetzt, liefert 422cannot-be-null.
Entscheidungstabelle
| id in data | Objekt sichtbar | Rolle zum Ändern | gesendete Felder gültig | Antwort |
|---|---|---|---|---|
| nein | – | – | – | 400 missing-id |
| ja | nein | – | – | 404 not-found |
| ja | ja | nein | – | 403 missing-permission|<rolle> |
| ja | ja | ja | nein | 422 validation-failed |
| ja | ja | ja | ja | 200, 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
- Das ganze Objekt ersetzen: Ersetzen mit PUT
- Welches Verb wann: PUT oder PATCH? Die null-Falle
- Was geprüft wird: Validierung