Worum es geht
Mit PUT {basis}/update/{id} ersetzt du ein Objekt. Was du in data schickst, ist der vollständige Zielzustand: So soll das Objekt danach aussehen, Feld für Feld.
PUT /api/rest/crm/customer/update/5a2b…
{
"data": {
"id": "5a2b…",
"name": "Muster GmbH",
"email": "neu@muster.de",
"phone": "+49 611 123456"
},
"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 stand vorher im Objekt, fehlt aber im PUT. Deshalb ist es jetzt leer. Die Antwort ist 200, response bestimmt wie beim Lesen, welche Felder zurückkommen, und ist Pflicht.
Vorher, Payload, Nachher
Eine Firma mit Name, Notiz, Hauptadresse (Referenz) und zwei Mitarbeitern (Liste). Die Mitarbeiter sind abhängige Kinder: Sie gehören zur Firma und werden mit ihr gelöscht.
| Feld | vorher | im PUT | nachher |
|---|---|---|---|
companyname | „CodamIC“ | "Codamic AG" | „Codamic AG“ |
note | „Stammkunde“ | fehlt | null |
logo | „logo.png“ | null | null |
mainAddress | Adresse A | fehlt | gelöst, Adresse A existiert weiter |
employees | Anna, Ben | [{ "id": Anna, …alle Felder… }] | nur Anna; Ben ist gelöscht |
Die Tabelle zeigt die drei Regeln für die drei Feldarten:
| Einfaches Feld | Einzelreferenz | Liste | |
|---|---|---|---|
| Feld fehlt oder ist null | wird geleert | wird gelöst; ein abhängiges Kind wird gelöscht | alle Mitglieder werden entfernt |
| Feld hat einen Wert | wird gesetzt | zeigt danach auf das genannte Objekt | wird genau zu dieser Liste (Zielzustand) |
Ob eine Referenz nur gelöst oder das Kind gelöscht wird, legt die Beziehung im Modell fest. Siehe Beziehungstypen und Recursive-Flags.
Die Stationen eines PUT
-
CIASFilterketteIst das Token gültig?↳ nein 401
-
CDMSFeldauswahlSteht eine
responseim Körper?↳ nein 400response -
CDMSSichtbarkeitGibt es das Objekt mit
data.id, und darf die Person es sehen? Gleiche Filter wie beim Lesen.↳ nein 404not-found -
CDMSModellrolleHat die Person das Recht,
customerzu ändern? Ebenso für jedes Kind, das mitgeändert wird.↳ nein 403missing-permission|<rolle> -
CDMSFelder übertragenJedes Feld des Modells wird auf den Wert aus
datagesetzt, fehlende auf leer. Verstöße gegen Regeln werden gesammelt. -
HookBefore-HooksHooks sehen das geänderte Objekt und dürfen es noch anpassen.
-
CDMSValidierungSind nach den Hooks alle Regeln erfüllt?↳ nein 422
validation-failedmit allen Verstößen -
DatabaseSpeichern und ZurücklesenÄnderung schreiben, After-Hooks, dann das Objekt mit der
responseneu lesen - 200 mit dem Objekt, wie es jetzt aussieht
Zwei Dinge fallen auf:
- Sichtbarkeit kommt vor der Rolle. Ein Objekt, das du nicht sehen darfst, liefert 404, auch wenn dir zusätzlich die Änderungsrolle fehlt. Siehe Warum Unsichtbares 404 liefert.
- Das Zurücklesen gehört zur Anfrage. Es läuft mit deinen Leserechten, in derselben Transaktion. Scheitert es, ist auch die Änderung nicht gespeichert.
_createdOn bleibt, wie es war, _updatedOn wird auf jetzt gesetzt. Alle Felder mit _ und die id überspringt CDMS beim Schreiben. Siehe Systemfelder.
Woher die ID kommt
Die id steht bei PUT zweimal im Request: im Pfad und in data. Maßgeblich ist data.id. Den Pfad wertet CDMS nicht aus.
| data.id | id im Pfad | Was passiert |
|---|---|---|
| vorhanden | gleich | das Objekt mit dieser id wird ersetzt |
| vorhanden | anders | das Objekt aus data.id wird ersetzt, ohne Fehler |
| fehlt | egal | 400 missing-id |
Kindobjekte in einem PUT
Referenzen und Listeneinträge kannst du als Objekt schicken. Was CDMS damit macht, hängt an zwei Fragen: Hat das Kind eine id? Erlaubt die Beziehung, Kinder anzulegen oder zu ändern?
Wann: Die Beziehung erlaubt kein Ändern der Kinder. Typisch für Verweise wie mainAddress.
-
1Client→CDMSschickt
"mainAddress": { "id": "a7…" } -
2CDMS→Databasesucht das Objekt
a7… -
3CDMS→Clientgibt es nicht → 404
missing-object|a7…|mainAddress -
4CDMSgibt es → die Referenz zeigt jetzt darauf; weitere Felder des Kindes bleiben unberührt
Ergebnis: Die Firma zeigt auf Adresse a7…. Die Adresse selbst ändert sich nicht.
Wann: Die Beziehung erlaubt das Ändern der Kinder. Typisch für abhängige Kinder wie employees.
-
1Client→CDMSschickt
"employees": [{ "id": "k1…", "firstname": "Anna", "lastname": "Schmidt" }] -
2CDMSersetzt das Kind
k1…ebenfalls mit PUT-Regeln: fehlende Felder des Kindes werden geleert -
3CDMSentfernt alle anderen Mitarbeiter, abhängige werden gelöscht
Ergebnis: Nur Anna bleibt, mit genau diesen Feldern. Schickst du nur { "id": "k1…" }, werden ihre Felder geleert, bei Pflichtfeldern kommt 422 employees[0].firstname cannot-be-null.
Wann: Du willst ein neues Kind anlegen.
-
1Client→CDMSschickt
"employees": [{ "firstname": "Cem", "lastname": "Yıldız" }] -
2CDMSBeziehung erlaubt Anlegen? → legt den Mitarbeiter an, mit Defaultwerten und CREATE-Regeln
-
3CDMS→Clienterlaubt nicht → 400
recursive-create-not-allowed|employees
Ergebnis: Cem ist angelegt und der Firma zugeordnet. Alle bisherigen Mitarbeiter sind entfernt, weil sie in der Liste fehlen.
Die vollständigen Regeln stehen unter Die vier Fälle beim verschachtelten Schreiben und Listen als Zielzustand.
Entscheidungstabelle
| Feldart | im PUT | Beziehung: abhängiges Kind | Nachher |
|---|---|---|---|
| einfaches Feld | fehlt / null | – | leer |
| einfaches Feld | Wert | – | neuer Wert |
| Einzelreferenz | fehlt / null | nein | gelöst, das Objekt bleibt bestehen |
| Einzelreferenz | fehlt / null | ja | das Kind wird gelöscht |
| Liste | fehlt / null / [] | nein | alle Verknüpfungen gelöst |
| Liste | fehlt / null / [] | ja | alle Kinder gelöscht |
| Liste | Teilliste | – | genau diese Mitglieder; nicht genannte werden gelöst bzw. gelöscht |
Fallen
Wie es weitergeht
- Nur einzelne Felder ändern: Ändern mit PATCH
- Welches Verb wann: PUT oder PATCH? Die null-Falle
- Was geprüft wird: Validierung
- Zwei Clients ändern gleichzeitig: Gleichzeitige Änderungen