appcore-api 1.0.3-rc

HTTP API host and transport contracts for AppCore Runtime.
Documentation

appcore-api

Command/query ingress admits at most 16 requests per host before collecting or decoding bodies. Router clones share this gate; independently constructed hosts do not. Saturation returns HTTP 503 without a waiting queue; body reception has a 10-second deadline (408), and oversized bodies return 413. Each admitted body is bounded by max_payload_bytes; raw body bytes are therefore bounded by 16 times that setting, not total process RSS. Decoded objects, response buffers and transport allocations are additional. Health/status bypass this gate. The separate process-wide blocking-dispatch gate remains in place.

English guide | Guia em português | Guide français

Runtime HTTP command/query/status DTOs, router and host.

Responsibility: HTTP command/query/status host and transport DTOs.

Internal dependencies: appcore-core, appcore-security and appcore-supervisor.

Main API: CommandRequest/CommandResponse, QueryRequest/QueryResponse, validation errors, CommandEndpoint, QueryEndpoint, ApiRouter, ApiRequest/ApiResponse, RuntimeHttpHost, HttpApiConfig, static status, application command/query capability policy, token verification and sync-log view.

Stable routes include health, status, command and query V1 endpoints. Business behavior is registered through command/query contracts; product REST resources do not belong in this crate.

HttpApiConfig::max_payload_bytes bounds the complete command/query HTTP body before JSON deserialization. Protected routes reject missing, malformed or duplicate Authorization headers.

The built-in TCP host closes a connection after 10 seconds without read progress, including a client that stops during HTTP headers. Because no request exists before the headers are complete, that case closes the socket instead of returning an HTTP status. A formed request whose body stalls still receives HTTP 408 from ingress middleware.

QueryRequest::validate measures its structured JSON through a bounded counting writer instead of allocating a complete encoded copy. The exact V1 byte limit and payload_bytes() compatibility method remain unchanged, and HTTP validates once before blocking dispatch.

The router owns one shared immutable RuntimeStaticInfo; cloning request state does not copy its peer lists, DNS seeds, paths or identity strings. Blocking dispatch takes ownership of command/query requests. Query audit keeps only the bounded query ID and name while the payload is in flight. Owned command paths use CommandRequest::into_envelope, which validates the same V1 fields and transfers the payload allocation into CommandEnvelope without copying its bytes. to_envelope remains for borrowed callers.

CommandTokenVerifier also has additive borrowed request methods. Their defaults materialize RequestValidationDetails and call the existing owned methods, so existing verifiers keep their behavior. The Runtime verifier overrides them to hash text or structured JSON directly without an owned payload copy.

The host capability policy authorizes application commands and queries before dispatch. Runtime-owned status queries remain outside application capability declarations.

Command and query dispatch share 16 process-wide blocking slots. The Tokio blocking pool uses the same ceiling, 1 MiB stacks and a five-second idle retirement. Saturation is rejected with HTTP 503 before work enters the queue.

Runtime hosts freeze ApiRouter query registration after bootstrap. Router clones share Arc endpoints, so direct facade, HTTP and peer RPC queries release the host-state mutex before calling an endpoint and independent queries can execute concurrently. query_names_iter exposes the frozen registry by reference for validation; query_names remains the deterministic owned API for output boundaries. The composition root uses the borrowed view, so a successful manifest check does not clone or sort the complete query catalog.

The 1.0.2-rc opt-in ReloadableRuntimeHttpHost keeps one listener while it health-checks and atomically switches routing generations. Requests already admitted keep the old router until completion; the old generation drains under a deadline. Prepare, post-switch health, or drain failure leaves or restores the previous generation. Generation numbers increase monotonically, reloads are serialized, and the owner retains at most one active and one retiring generation. A failed generation blocks another reload until its final request releases it. Payload-free snapshots expose active/retiring admission and in-flight counts without retaining a history. Cancelling after the switch restores the previous generation synchronously. A listener-address change fails explicitly and requires a separately prepared listener generation in the composition root. RuntimeHttpHost remains unchanged.

Composition roots that need bind-before-start validation can call run_on_listener_until_shutdown with an already bound TCP listener. Ownership is transferred to the host and shutdown remains graceful.

When composed with appcore-sync 1.0.2-rc, SyncLogView::len and is_empty are fallible. Private status JSON returns sync_log_len: null together with sync_log_observation_ok: false when live persistence cannot be observed; it never substitutes a stale static count.

The built-in runtime.audit query caps limit at 1,000. It captures shared record and entry snapshots while holding only short locks, then materializes the newest requested page after those locks are released; it never deep-clones the complete 10,000-item audit queues for a bounded response.

runtime.events follows the same rule: it borrows at most the newest 1,000 events from a shared snapshot after releasing the host and event-bus locks. The response format remains unchanged and continues to omit opaque event payloads.

HttpCommandAuth::default() requires authentication and fails closed until a token verifier is configured. Only insecure_local_for_testing() explicitly disables command/query authentication for controlled local tests. /v1/health remains intentionally public. Rejected command authorization is audited with normalized metadata and never records credentials, payloads or idempotency keys.

Maturity: strict and stable RC HTTP V1 surface.

cargo test -p appcore-api

Stable documentation

Stable ID: ACR-009. See the supplemental architecture and integration guide. This permanent ID remains valid if the wiki page moves.