Skip to content

apomesh-rest-api

apomesh-rest-api is a transport crate: the REST/JSON external API and the Server-Sent Events (SSE) event tail. It is the human-facing parallel to the gRPC programmatic wire — an axum + tower-http server whose handlers are thin adapters that extract HTTP inputs, call a substrate workflow, and serialize the typed outcome back to JSON. It runs no business logic; the same workflows the gRPC surface calls live in apomesh-orchestrator and apomesh-substrate. This is transport parity, not a second API: a session started over REST and one started over gRPC take the identical substrate path. Touch this crate for the HTTP surface — route families, the generated OpenAPI document, the SSE projection, and the HTTP auth middleware.

  • Layer: transports. See The dispatch lifecycle for how every transport converges on one session workflow, and Identity & authorization for the SessionAuth backend both transports share.
  • Depends on: apomesh-protocol (the wire types the JSON shapes mirror), apomesh-substrate (the domain types and primitives the handlers call), and apomesh-orchestrator (the transport-blind create_session_workflow the session routes delegate to).
  • Consumed by: apomesh-orchestrator-bin — the daemon binary constructs the RestAppState, calls build_router, and serves the listener beside the gRPC service. It is the crate’s only consumer; the transport is wired, not depended on by the substrate layers.
  • The router assemblybuild_router mounts every route family under /api/v1/, layers the auth middleware onto the protected sub-router, and attaches the standard tower-http stack (CORS, compression, request-id, body-limit, timeout, trace).
  • The route families — thin translate-and-delegate handlers grouped by resource (sessions, tenants, quotas, published agents and skills, strategy configs, tokens, audit, HITL, provider config, the memory reads, assets).
  • OpenAPI 3.x generation — the ApiDoc aggregator drives compile-time derivation from each handler’s #[utoipa::path] annotation and serves the document as the contract artifact.
  • The SSE event projectionroutes::events adapts the substrate’s EventBus::tail_from subscription (the same primitive the gRPC TailEvents RPC uses) into a text/event-stream response, one SSE frame per envelope.
  • HTTP authentication — the oauth_extract middleware bridges the HTTP bearer token to the substrate’s SessionAuth, installing the resolved TenantContext for downstream handlers. No business logic — auth and shape translation only.
  • build_routerbuild_router(state: RestAppState, http: HttpConfig) -> axum::Router; the entry point that mounts every family, the middleware, and the OpenAPI document into one router.
  • serveserve(router, config: RestServerConfig); binds the listener (plaintext, or TLS from the same Config::auth.tls block the gRPC listener reads) and runs forever, returning the closed-enum RestServerError on failure.
  • RestAppState — the aggregated substrate handles (OrchestratorRuntime, OrchestratorDaemon, registries, SessionAuth); every field is an Arc, so axum’s State extractor clones it per request cheaply.
  • RestServerConfig / HttpConfig — the listener config (address + optional TLS) and the operator HTTP-surface policy (CORS origins, max body bytes).
  • ApiDoc / OPENAPI_JSON_PATH — the utoipa aggregator and the /api/v1/openapi.json path the served document is exposed at.
  • routes::*::router() — each resource family exposes a router() returning an OpenApiRouter; build_router merges them.
  • routes::events (SSE tail)GET /api/v1/events?session=<id>; the live event-bus stream with Last-Event-ID resume.
  • auth::oauth_extract — the middleware that runs SessionAuth.authenticate and installs the TenantContext.

The route families are deliberately not enumerated here. The served OpenAPI document at GET /api/v1/openapi.json is generated from the handlers and is the exhaustive, always-current surface — consult it for exact request and response shapes.

The daemon binary owns the wiring: it builds one RestAppState from the same Arc-shared substrate handles the gRPC service holds, then mounts and serves the router. The shape (from apomesh-orchestrator-bin):

use apomesh_rest_api::{build_router, serve, HttpConfig, RestServerConfig};
// `rest_state: RestAppState` and `rest_cfg: RestServerConfig` are built from
// the daemon's shared handles + `Config::auth.tls`.
let router = build_router(rest_state, HttpConfig::default());
serve(router, rest_cfg).await?;

For driving the running surface — starting a session, tailing events, and cancelling over HTTP — see the REST + SSE how-to, which walks the curl calls against the local stack.