What this is about
A write operation consists of many steps: check rights, transfer values, check rules, save, read back. The hooks sit at two fixed points in between. Exactly where decides what a hook can do and what CDMS still checks afterwards.
The most important rule: CDMS first walks through the whole object tree of the request and queues the hooks for each object on the way. This pass over the object and all its children is called recursion. Only then do the hooks run, and they run before validation gives its verdict.
The steps of a create, PUT or PATCH
-
1Client→CDMSsends the changed object
-
2CDMScheck visibility, load the stored object (only with PUT and PATCH)
-
3CDMSrecursion: for the object and every child, check the role, transfer values, remember rule violations, queue hooksA missing role stops here, before a single hook has run. A dependent child that drops out of a list is already marked for removal here.
-
4Hookbefore hooks of all queued objectsThey see the object with all transferred values and may still change it.
-
5CDMSvalidation: check each remembered violation again against the value that is now on the object
-
6CDMSviolations left → 422 with all violations
-
7CDMS→Databasehands the object to the database, new objects get their
id -
8Hookafter hooks of all queued objects
-
9CDMS→Databaseflush: the SQL is executed, the database checks its rules, for example unique values
-
10CDMS→Databasereads the object back with the
responseof the request -
11HookREAD hook for every object read back
-
12CDMS→Clientcommit, then 200 with the object
Three points are fixed here:
- Roles before hooks. All role checks of the recursion happen before any hook runs. If a role is missing, not a single hook runs. See Model roles.
- Hooks before the verdict. Validation only remembers violations during the recursion. Whether they count, it decides only after the before hooks. See Validation.
- After hooks before the flush. When the after hooks run, the database has not yet checked its own rules. A duplicate value in a unique field only shows up afterwards. See One request, one transaction.
Why a before hook may fill a required field
An example: the model order has the required field orderNr. The client does not know the number, a before hook assigns it.
-
1Client→CDMSsends
{ "data": { "customer": { "id": "k-7" } } } -
2CDMSrecursion:
orderNris missing → violationcannot-be-nullis remembered, not reported -
3Hookbefore hook sets
orderNr = "A-2026-0042" -
4CDMSchecks
orderNragain: now filled, the violation disappears -
5CDMS→Databasesaves the order with the number from the hookResult: 200, the response contains
orderNr
The second check applies all rules of the field, not only the one that was violated before. If the hook sets an empty text instead of the missing number, CDMS reports cannot-be-empty, because the field now breaks this rule.
What CDMS still checks after the before hooks
The second check only covers fields that had a violation. A field whose value was valid during the recursion is not checked again by CDMS.
| Field had a violation before | Value after the hook | What happens |
|---|---|---|
| yes | valid | violation disappears, saved |
| yes | invalid | 422 with the rule the new value breaks |
| no | valid | saved |
| no | invalid | no check by CDMS, saved as long as the database accepts it at flush |
So the validation rules are mainly a protection against wrong input from the client. What your hook writes is your responsibility. This applies even more to PATCH: PATCH only checks the sent fields. A field that the hook sets but the client did not send is not checked by CDMS at all.
The variants per operation
When: POST /create, PUT /update/{id}, PATCH /update/{id}
Exactly as above: recursion, before hooks, validation, saving, after hooks, flush, read-back with READ hook, commit.
Result: The operation in the hook is called CREATE, UPDATE or PATCH, per object: a new child in a PUT gets CREATE.
When: DELETE /delete/{id}
-
1CDMScheck visibility, load the object
-
2CDMSrecursion: check the delete role per object, mark dependent children for removal, unlink other relations, queue hooks
-
3Hookbefore hooks (
DELETE) -
4CDMS→Databasehands the object over for removal
-
5Hookafter hooks (
DELETE) -
6CDMS→Databaseflush, commit, 200 without body
Result: No validation, no read-back, no READ hook. See How a DELETE runs.
When: POST {basis}/{id}/rollback/{revision}
-
1CDMScheck visibility and the rollback role
-
2Hookbefore hook (
ROLLBACK) with the current state -
3CDMS→Databaserestores the revision
-
4Hookafter hook (
ROLLBACK) with the restored state -
5CDMS→Databaseflush, read-back with READ hook, commit
Result: No recursion and no validation: the hooks only run for the addressed object. See Rolling back to an old state.
The order of the hook calls among each other
For a single object it is simple: first all before hooks of its model by @Order, later all after hooks by @Order. If the request writes several objects, for example a parent with children, there is a fixed order across all objects. It is described in Hooks for nested objects and cascades.
Pitfalls
Where to go next
- Which hook points exist: Hooks: types and timing
- In which order parents and children come up: Hooks for nested objects and cascades
- The stations of a create: Creating an object