Worum es geht
In einem Request kannst du nicht nur ein Objekt schreiben, sondern auch seine Kinder: die Objekte in seinen Beziehungsfeldern. Eine Firma mit neuen Mitarbeitern anlegen, eine Rechnung mit ihren Positionen ändern, einen Mitarbeiter einer bestehenden Abteilung zuordnen. Das heißt verschachteltes Schreiben.
Für jedes Kind im Request stellt CDMS zwei Fragen:
- Hat das Kind eine
id? - Erlaubt die Beziehung das Passende, also das Flag
CREATEbzw.UPDATE?
Der Entscheidungsbaum
flowchart TB
K["Kind im Request"] --> I{"hat eine id?"}
I -->|nein| C{"Flag CREATE?"}
C -->|ja| A1["1 · anlegen"]
C -->|nein| A4["4 · abgelehnt: 400"]
I -->|ja| E{"gibt es das Objekt?"}
E -->|nein| A5["404"]
E -->|ja| U{"Flag UPDATE?"}
U -->|ja| A2["2 · mitändern"]
U -->|nein| A3["3 · nur verknüpfen"]
Alle vier Fälle in einem Request
Eine Abteilung, deren Beziehung employees die Flags CREATE und UPDATE hat, und deren Beziehung location keine Flags hat:
PUT /api/rest/department/update/d1…
{
"data": {
"id": "d1…",
"name": "IT",
"employees": [
{ "firstname": "Ada", "lastname": "Lovelace" },
{ "id": "e2…", "firstname": "Alan", "lastname": "Turing" }
],
"location": { "id": "l7…", "city": "Wiesbaden" }
},
"response": ["+"]
}Ada → Fall 1: wird angelegt (kein id, CREATE)
Alan → Fall 2: wird geändert (id, UPDATE)
location → Fall 3: wird nur verknüpft (id, kein UPDATE),
"city" wird ignoriertHätte location ein Kind ohne id, wäre das Fall 4: location hat kein CREATE, die ganze Anfrage scheitert mit 400 recursive-create-not-allowed|location.
Die vier Fälle im Einzelnen
Wann: Kind ohne id, Beziehung mit CREATE.
-
1CDMSprüft die Anlegerolle des Kindmodells (oder eine Feldrolle am Beziehungsfeld)
-
2CDMSlegt das Kind an: eigene
id,_createdOn, Defaultwerte, CREATE-Regeln -
3CDMSverbindet es mit dem Elternobjekt, beide Seiten
Ergebnis: Das Kind existiert und gehört zum Elternobjekt. Das gilt bei Create, PUT und PATCH gleich.
Wann: Kind mit id, Beziehung mit UPDATE.
-
1CDMS→Databasesucht das Kind
-
2CDMSprüft die Änderungsrolle des Kindmodells (oder eine Feldrolle)
-
3CDMSändert das Kind nach den Regeln des Verbs: bei Create und PUT ersetzt es das Kind, bei PATCH ändert es nur die gesendeten Felder
-
4CDMSverbindet es mit dem Elternobjekt
Ergebnis: Achtung bei PUT: { "id": "e2…" } allein leert alle Felder des Kindes, bei Pflichtfeldern kommt 422 employees[0].firstname cannot-be-null.
Wann: Kind mit id, Beziehung ohne UPDATE.
-
1CDMS→Databasesucht das Kind
-
2CDMS→Clientgibt es nicht → 404
-
3CDMSprüft, ob du das Kind lesen dürftest: Leserolle (oder Lese-Feldrolle) und Zeilenfilter
-
4CDMS→Clientdarfst du es nicht sehen → 404, als gäbe es die
idnicht -
5CDMSverbindet es mit dem Elternobjekt; weitere Felder des Kindes werden ignoriert
Ergebnis: Das Kind bleibt, wie es ist. Nur die Verbindung ist neu. Verlangt wird die Leseberechtigung des Kindes – nicht seine Änderungsrolle, denn das Kind ändert sich ja nicht.
Wann: Kind ohne id, Beziehung ohne CREATE.
-
1CDMSFlag CREATE fehlt
-
2CDMS→Client400
recursive-create-not-allowed|<feld>, nichts wird gespeichert
Ergebnis: So verhindert CDMS, dass über einen Verweis versehentlich neue Objekte entstehen.
Listen bei PATCH
In einer Liste gelten bei PATCH dieselben vier Fälle wie bei Create und PUT und wie bei einer Einzelreferenz. Anders ist nur, wie ein Kind mit UPDATE geändert wird: PATCH ändert nur die gesendeten Felder, PUT ersetzt das Kind.
| Create und PUT | PATCH | |
|---|---|---|
| Eintrag mit id, ohne UPDATE | wird nur verknüpft, gesendete Felder werden ignoriert | wird nur verknüpft, gesendete Felder werden ignoriert |
| Eintrag ohne id, ohne CREATE | 400 recursive-create-not-allowed|<feld> | 400 recursive-create-not-allowed|<feld> |
| Eintrag mit id, mit UPDATE | Kind wird ersetzt | nur die gesendeten Felder ändern sich |
Entscheidungstabelle
| id | Objekt existiert | Flag | Verb, Feldart | Ergebnis |
|---|---|---|---|---|
| nein | – | CREATE | alle | anlegen |
| nein | – | kein CREATE | alle | 400 recursive-create-not-allowed|<feld> |
| ja | nein | – | Create, PUT (Einzelreferenz) | 404 missing-object|<id>|<feld> |
| ja | nein | – | PATCH | 404 missing-object-for-field|<id>|<feld> |
| ja | ja | UPDATE | alle | mitändern (PUT ersetzt, PATCH ändert) |
| ja | ja | kein UPDATE | alle | nur verknüpfen |
Bei einem abstrakten Zielmodell braucht ein neues Kind zusätzlich @type, sonst weiß CDMS nicht, welchen Untertyp es anlegen soll. Fehlt er, kommt 400 missing-type-for-abstract-field mit dem Pfad des Feldes: bei PATCH …|mainPhone, bei Create und PUT …|data.mainPhone. Ein unbekannter Typ liefert 400 unknown-type-for-abstract-field|<pfad>|<typ>.
Rollen der Kinder
Jedes Kind, das CDMS anlegt, ändert oder löscht, wird mit den Rollen seines Modells geprüft. Eine Feldrolle am Beziehungsfeld kann die Rolle des Kindmodells ersetzen, aber nur für diesen Weg. Fehlt beides, scheitert die ganze Anfrage mit 403 missing-permission|<rolle>. Siehe Beziehungstypen und Recursive-Flags und Rechte auf Beziehungen (Feldrollen).
Strict Mode aus
Der Strict Mode ist der Standard: Was nicht erlaubt ist, wird mit einem Fehler abgelehnt. Eine Installation kann ihn abschalten. Dann lehnt CDMS weniger ab und lässt stattdessen weg:
| Fall | Strict Mode an | Strict Mode aus |
|---|---|---|
| neues Kind in einer Liste, kein CREATE | 400 | Eintrag wird übergangen |
| neues Kind als Einzelreferenz, kein CREATE | 400 | das Feld wird leer |
| Rolle des Kindes fehlt | 403 missing-permission|<rolle> | 403 missing-create-role / missing-update-role / missing-delete-role |
Siehe Strict Mode: Fehler oder still ignorieren.
Fallen
Wie es weitergeht
- Was mit Mitgliedern passiert, die in der Liste fehlen: Listen als Zielzustand
- Wer die Gegenseite pflegt: Beide Seiten einer Beziehung
- Die Flags: Beziehungstypen und Recursive-Flags