dispatch (dispatchRqo)
See also: JSON API v1 · dd_core_api
dispatchRqo is the server's request router: it receives the decoded RQO, runs it through the security gates, and calls the registered handler. It is an internal entry point — clients never address it directly, they POST an RQO to the JSON endpoint (see JSON API v1).
Routing is table-driven, not reflective. The ACTION_REGISTRY map in src/core/api/dispatch.ts explicitly binds every (dd_api, action) pair to a handler function; a pair that is not in the map does not exist and is refused at the first gate. There is no dynamic method lookup and no autoloader fallback, so the registry is the single source of truth for what the API can do.
How it works
src/server.tsreceives the POST, parses it, and validates the body against the RQO Zod schema (src/core/concepts/rqo.ts).- It calls
dispatchRqo(rqo, context), which looks the handler up inACTION_REGISTRY[dd_api][action]and runs the security gates in order — allowlist → authentication → CSRF → request-scoped language → per-action permission checks. See Security gates. - The handler bodies live in
src/core/api/handlers/<dd_api>.ts, one module per API class.dispatch.tsitself holds only the registry, the gates, and the response envelope. - Any handler exception is caught by the one converter and degraded to the envelope-v2 failure body (
ok: falseplus a codederror) rather than a raw 500, because the client decides failure by readingokfrom a parsed JSON body.
Notes for integrators
- A new action becomes callable only by registering a handler in
ACTION_REGISTRY. Adding a method to a module is not enough. - The
ApiRequestContext(request id, client IP, session, CSRF candidate, resolved principal) is created by the HTTP layer and threaded explicitly into every handler. There are no request-scoped globals, so one caller's identity or language cannot bleed into another's request in the long-lived server process.
Contract
- Purpose: validate the request, enforce the security gates, and call the target handler. Wraps exceptions and returns a normalized response.
- Accepts: the decoded RQO (
dd_api,action,source,options,sqo,data, …) plus theApiRequestContext. - Returns: the handler's
ApiResult({ status, body }), or on error{ ok: false, request_id, error: { code, category, message, label_key, retryable } }.
Example request
{
"dd_api": "dd_core_api",
"action": "read",
"source": { "section_tipo": "rsc167", "mode": "list" },
"sqo": { "limit": 10 }
}
Example response
{
"ok": true,
"request_id": "c0ffee03",
"data": { "context": [], "data": [] }
}
Registered API classes
Each (dd_api, action) pair the registry binds lives in one of these class pages (the full index is on JSON API v1):
- dd_core_api — section/record lifecycle and page context.
- dd_utils_api — system and utility helpers.
- dd_tools_api · dd_ts_api · dd_area_maintenance_api.
- dd_diffusion_api — publication / diffusion process control.
- dd_rag_api — semantic retrieval (RAG) and image similarity.
- dd_identify_api — object identification: matches, image identification, proposals, Type promotion.
- dd_external_api — search a third-party catalogue through the engine.
- dd_component_portal_api · dd_component_text_area_api · dd_component_av_api · dd_component_3d_api · dd_component_info.
- dd_mcp_api — the in-process assistant / MCP bridge.
- dd_error_report_api — machine-to-machine error-report intake.