Worum es geht
Mit POST {basis}/create legst du ein neues Objekt an. Im Körper stehen zwei Dinge:
| Teil | Inhalt |
|---|---|
data | die Felder des neuen Objekts, ohne id |
response | welche Felder du in der Antwort zurückhaben willst, wie beim Lesen |
POST /api/rest/crm/customer/create
{
"data": { "name": "Muster GmbH", "email": "info@muster.de" },
"response": ["+"]
}{
"data": {
"id": "5a2b…",
"_createdOn": "2026-09-21 10:15:02",
"_updatedOn": null,
"name": "Muster GmbH",
"email": "info@muster.de",
"status": "NEW"
},
"meta": { "error": false }
}Die Antwort ist 200. id, _createdOn und _updatedOn kommen immer mit. status hat der Client nicht geschickt: Der Wert NEW ist der Defaultwert des Feldes.
Die Stationen eines Create
-
CIASFilterketteIst das Token gültig?↳ nein 401
-
CDMSFeldauswahlSteht eine
responseim Körper?↳ nein 400response -
CDMSModellrolleDarf die Person
customeranlegen? Ebenso jedes Kind, das mit angelegt wird.↳ nein 403missing-permission|<rolle> -
CDMSFelder übertragenSystemfelder setzen, Werte aus
dataübernehmen, leere Felder mit Defaultwerten füllen, Kinder anlegen oder verknüpfen, Verstöße sammeln↳ nein 400 / 404 bei Kindern, siehe unten -
HookBefore-HooksHooks sehen das neue Objekt und dürfen es noch ändern. Eine
idhat es noch nicht. -
CDMSValidierungSind nach den Hooks alle Regeln erfüllt?↳ nein 422
validation-failedmit allen Verstößen -
DatabaseSpeichernDie Zeile wird geschrieben, die Datenbank vergibt die
id. Danach laufen die After-Hooks.↳ nein 409already-exists, z. B. doppelter eindeutiger Wert -
CDMSZurücklesenDas neue Objekt wird mit der
responsegelesen, mit den Leserechten der Person.↳ nein 403 / 404, und auch das Anlegen ist zurückgenommen - 200 mit dem neuen Objekt
Was CDMS beim Anlegen selbst setzt
| Feld | Wert |
|---|---|
id | eine neue UUID, beim Speichern |
_createdOn | jetzt |
_updatedOn | bleibt leer, bis zur ersten Änderung |
_userId | die angemeldete Person, nur bei Modellen mit dem Scope „Benutzer“ |
@type | der konkrete Typ; bei einem abstrakten Modell wählt ihn der Client |
| Felder mit Default | der Defaultwert, wenn der Client keinen Wert schickt |
Schickt der Client eine id oder ein Feld mit _ mit, ignoriert CDMS das ohne Fehler. Siehe Systemfelder. In welcher Datenbank das Objekt landet, ergibt sich aus dem Mandanten der Anfrage, ein eigenes Mandantenfeld gibt es nicht. Siehe Welche Datenbank? Das Persistenzziel
Der Ablauf im Detail
sequenceDiagram
participant C as Client
participant R as REST-Layer
participant S as System-Layer
participant H as Hooks
participant DB as Datenbank
C->>R: POST /create { data, response }
R->>R: response auflösen, Dateien übernehmen
R->>S: createObject(DTO)
S->>S: Rolle prüfen, _createdOn setzen
S->>S: Felder übertragen, Defaults einsetzen,<br/>Kinder anlegen, Verstöße sammeln
S->>H: Before-Hooks (Eltern vor Kindern)
S->>S: Verstöße erneut prüfen → 422?
S->>DB: INSERT, id wird vergeben
S->>H: After-Hooks
S->>DB: flush
S->>DB: mit response zurücklesen
S-->>R: DTO
R-->>C: 200 { data, meta }
Die Hooks laufen vor der Validierung. Ein Before-Hook darf also ein Pflichtfeld füllen, das der Client gar nicht kennt, etwa eine Kundennummer. Mehr unter Hooks: Arten und Zeitpunkte.
Alle Ausprägungen
Wann: Der Normalfall.
-
1Client→CDMSschickt
POST /crm/customer/createmitdataundresponse -
2CDMSprüft die Rolle, übernimmt die Felder, setzt Defaults
-
3HookBefore-Hooks
-
4CDMS→Databaseprüft die Regeln, speichert, liest zurück
-
5CDMS→Clientliefert das neue Objekt
Ergebnis: 200 mit dem neuen Objekt und seiner id.
Wann: Das Modell ist ein Datei-Modell oder hat Datei-Felder.
Es gibt zwei Wege. Multipart: POST /create/upload mit einem Teil data (das JSON) und den Dateien im Teil files. Ein Datei-Objekt in data findet seine Datei über den Namen: name im Objekt muss gleich dem Dateinamen des Teils sein. Base64: POST /create wie gewohnt, der Inhalt steht als Text in content des Datei-Objekts. Fehlt beim Datei-Modell die passende Datei, kommt 400 file-part-missing|<name>.
Ergebnis: 200, die Datei liegt im Speicher. Siehe Hochladen.
Wann: Das Modell hat genau ein Objekt je Scope, z. B. Einstellungen. Pfad: POST /create, ohne id.
-
1Client→CDMSschickt
POST /crm/einstellungen/create -
2CDMS→DatabaseGibt es schon ein Objekt in diesem Scope?
-
3CDMS→Clientja → 400
object-already-exists|use-update -
4CDMSnein → legt es an wie ein normales Objekt
Ergebnis: 200. Danach änderst du es mit PUT /update oder PATCH /update. Siehe Singletons.
Wann: Du legst über die Hub-API eines abstrakten Modells an, z. B. /crm/kunde/create.
-
1Client→CDMSschickt
{ "data": { "@type": "crm.privatkunde", "name": "Anna Muster" }, "response": ["+"] } -
2CDMSliest
@typeund damit die Felder des Untertyps -
3CDMS→Client
@typefehlt → 400missing-type-for-abstract-field|data; unbekannter Typ → 400unknown-type-for-abstract-field|data|<typ> -
4CDMSgibt die Anfrage an die API des Untertyps weiter, mit dessen Rollen, Regeln und Hooks
Ergebnis: 200 mit "@type": "crm.privatkunde". Siehe Abstrakte Modelle.
Wann: Du legst eine Firma mit ihren Mitarbeitern in einem Request an, oder verknüpfst sie mit bestehenden Objekten.
-
1Client→CDMSschickt
"employees": [{ "firstname": "Anna", "lastname": "Schmidt" }], "mainAddress": { "id": "a7…" } -
2CDMSKind ohne
id→ wird angelegt, wenn die Beziehung das erlaubt, mit eigener Rollenprüfung, eigenen Defaults und_createdOn -
3CDMS→ClientBeziehung erlaubt kein Anlegen → 400
recursive-create-not-allowed|employees -
4CDMSKind mit
id→ wird verknüpft -
5CDMS→Client
idgibt es nicht → 404missing-object|a7…|mainAddress -
6CDMS→Databasespeichert alles in einer Transaktion
Ergebnis: 200. Scheitert ein Kind, wird auch die Firma nicht angelegt. Siehe Die vier Fälle beim verschachtelten Schreiben.
Entscheidungstabelle
| response im Körper | Rolle zum Anlegen | Regeln erfüllt | eindeutige Werte frei | Leserolle fürs Zurücklesen | Antwort |
|---|---|---|---|---|---|
| nein | – | – | – | – | 400 response |
| ja | nein | – | – | – | 403 missing-permission|<rolle> |
| ja | ja | nein | – | – | 422 validation-failed |
| ja | ja | ja | nein | – | 409 already-exists |
| ja | ja | ja | ja | nein | 403 missing-permission|<leserolle>, nichts angelegt |
| ja | ja | ja | ja | ja | 200 mit dem neuen Objekt |
Die Tabelle beschreibt den Standard: Strict Mode an und Zurücklesen im Modus STRICT. Im Modus LENIENT wird erst gespeichert und dann gelesen. Scheitert dann nur das Lesen, bleibt das Objekt angelegt und die Antwort nennt seine id. Siehe Anlegen und Zurücklesen: STRICT oder LENIENT.
Fallen
Wie es weitergeht
- Felder, die sich selbst füllen: Defaultwerte
- Was geprüft wird: Validierung
- Danach ändern: Ersetzen mit PUT und Ändern mit PATCH
- Was in einer Transaktion passiert: Ein Request, eine Transaktion