REST Interface
Type: Reference / Specification
Path: rest/
1. Purpose
The REST interface exposes the Action Engine over HTTP via Hono. It implements a single-POST-endpoint architecture where all service communication flows through one route, discriminated by an intent field in the request body.
1.1 Responsibilities
- Request validation — Validates incoming JSON against a Zod schema before processing
- Intent routing — Dispatches
explore,execute, andschemaintents to dedicated handlers - Response mapping — Converts internal
Result<T, E>types to theExternalResponseshape at the HTTP boundary - Middleware application — CORS, rate limiting, and static file serving
- Diagnostics — Emit request routing information via
createDiagnosticsLogfromutils/diagnostics-log.tswhendiagnosticsis enabled. Seedocs/internals/logging.mdsection 7.
1.2 Non-Goals
- Business logic — The REST layer does not contain domain logic. It delegates to the engine.
2. Architecture
The REST module is split into three files to stay under the 400 LOC limit:
3. Endpoints
3.1 POST {baseUrl}/services
The single endpoint for all service interactions. The request body must conform to ExternalRequest:
The body is validated against a Zod schema. Invalid JSON or missing fields return 400.
3.2 GET /status
Health check endpoint. Only registered when config.enableStatus is true.
Returns:
3.3 404 Handler
All unmatched routes return:
4. Intent Handlers
Intent dispatch uses an object lookup (intentHandlers) rather than switch/if-else.
4.1 Explore
Discovers services and actions.
4.2 Execute
Runs an action through the engine pipeline. Wildcards are rejected — both service and action must be specific.
Calls engine.executeAction(service, action, payload, nileContext) and maps the result.
4.3 Schema
Exports Zod validation schemas as JSON Schema (via z.toJSONSchema() from Zod v4).
Actions without a validation schema return null. Schema conversion failures are caught by safeTrySync and also return null.
5. Response Format
All responses use the ExternalResponse shape:
The toExternalResponse function handles the Result to ExternalResponse mapping:
Ok(value)— if value is a plain object, it becomesdatadirectly. Arrays and primitives are wrapped as{ result: value }.Err(message)—status: false, message is the error string,datais empty.
HTTP status codes: 200 for success, 400 for failures and validation errors, 404 for unmatched routes.
6. Middleware
6.1 CORS
Applied first via applyCorsConfig from cors/cors.ts. See docs/internals/cors.md.
6.2 Rate Limiting
File: rest/middleware.ts — applyRateLimiting
Only applied when config.rateLimiting.limitingHeader is set. Uses hono-rate-limiter.
- Client key is extracted from the configured request header
- If the header is missing, falls back to a shared
__unknown_client__key (graceful degradation, not a crash) - Defaults: 100 requests per 15-minute window
6.3 Static File Serving
File: rest/middleware.ts — applyStaticServing
Only applied when config.enableStatic is true. Supports both "bun" and "node" runtimes.
- Serves files from
./assetsat/assets/* - Dynamically imports the runtime-specific adapter (
hono/bunfor Bun,@hono/node-server/serve-staticfor Node) - The import result is cached after first successful load
- Import failures are caught by
safeTry— static serving is silently skipped
7. Key Types
7.1 RestConfig
7.2 RateLimitConfig
7.3 ExternalRequest
7.4 ExternalResponse
8. Constraints
- Single POST endpoint — All service interactions go through
POST {baseUrl}/services. No per-action routes. - No streaming — Responses are JSON only. No SSE or chunked transfer.
- Rate limiter requires header — Without
limitingHeader, rate limiting is not applied at all.
9. Failure Modes
- Invalid JSON body — Returns
400with "Invalid or missing JSON body" - Schema validation failure — Returns
400with Zod issue details indata.errors - Wildcard in execute — Returns
400with descriptive message - Missing service/action — Engine returns
Err, mapped to400viatoExternalResponse - Handler crash — Caught by
safeTryin the engine pipeline, returned asErr