Batch endpoints
Any entity with CRUD enabled gets three transactional batch
endpoints under the _batch suffix. All items in one request run in
a single database transaction: the first per-item failure rolls back
the whole transaction.
Routes
| Method | Path | Body |
|---|---|---|
POST | /{table}/_batch | {"items":[ {…}, {…}, … ]} |
PATCH | /{table}/_batch | {"items":[ {"id":"x", …}, … ]} |
DELETE | /{table}/_batch | {"ids":["x","y", …]} |
Response envelope
{ "committed": true, "results": [ { "index": 0, "data": { "id": "p1", "title": "A" } }, { "index": 1, "data": { "id": "p2", "title": "B" } } ]}
committed: true→ HTTP 200, the transaction was applied.committed: false→ HTTP 400, the transaction was rolled back.resultsis always in input order; every input index appears.- The first per-item failure populates
error(and optionally
fieldsfor validation failures) on that index. Later indices are
marked"skipped": true. - On
committed: falseno result carriesdata— errors and
fieldsremain.
Limits
MaxBatchSize = 100items per request. Go over that and you get
400 Bad Requestbefore any item runs.items(orids) can't be empty.
Behaviour & guarantees
- Atomic. One transaction; one commit or one rollback.
- Hooks run inside the transaction.
BeforeCreate,AfterUpdate,
etc. fire per item. A hook error rolls back the whole batch. - Events fire only on commit.
entity.createdetc. fire after a
successful commit, in input order, one per item — never on rollback. - No partial success. If you need "skip failures and keep the
rest", makeMaxBatchSizeindividual calls instead.
Examples
curl -X POST http://localhost:8080/posts/_batch \ -H 'Content-Type: application/json' \ -d '{"items":[ {"title":"First"}, {"title":"Second"}, {"title":"Third"} ]}'curl -X PATCH http://localhost:8080/posts/_batch \ -H 'Content-Type: application/json' \ -d '{"items":[ {"id":"p1","status":"published"}, {"id":"p2","status":"archived"} ]}'curl -X DELETE http://localhost:8080/posts/_batch \ -H 'Content-Type: application/json' \ -d '{"ids":["p1","p2","p3"]}'
Common mistakes
- Treating a non-committed response as a 200. It's a 400. Check
committedbefore you trustresults[*].data. - Counting on event ordering across batches. Within a batch,
events fire in input order. Across overlapping batches, order
depends on transaction commit order — don't count on it. - Sending more than 100 items. Split it client-side.
- Mixing batch and per-item requests in a saga. Mixing makes
rollback semantics ambiguous. Pick one.