Skip to main content

appcore-api

Published package

Stable 1.0.0 · MSRV Rust 1.89 · crates.io · docs.rs · source

Crate-owned guide and examples

The Runtime repository maintains the detailed guide, basic example, and intermediate example. The wiki summarizes the public boundary; API and executable details live beside the crate code.

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

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

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

Use it to expose Runtime-owned routes and register application query behavior. Do not add product REST resources or business schemas. Applications reach its contracts through the opt-in appcore-sdk/api namespace; the deployment executable owns HTTP hosting.

Application queries are authorized by the composed capability policy before the application router runs. Runtime-owned status queries remain outside the application capability catalog.

On the current 1.0 line, Runtime hosts freeze ApiRouter query registration after bootstrap. Router snapshots share immutable endpoints via Arc; direct facade, HTTP and peer RPC dispatch release the host-state mutex before calling an endpoint. Independent queries therefore execute concurrently, and late registration fails with router_frozen. query_names_iter lets manifest validation borrow this immutable registry; the deterministic owned query_names method remains available for output. Across 1,024 queries, the borrowed scan measured 28.63 us p50 and 2.41 MiB peak RSS versus 183.26 us and 2.55 MiB for full materialization.

The built-in runtime.audit query limits each response to at most 1,000 newest items. It captures shared record and entry snapshots under short locks and materializes only that page after releasing them, instead of deep-cloning both complete 10,000-item queues. Selecting 1,000 of 10,000 measured 2.06 us p50 and 11.88 MiB peak RSS, versus 4.16 ms and 20.33 MiB for the old full copies.

runtime.events follows the same snapshot boundary, caps the newest page at 1,000 and continues to omit opaque payloads from its unchanged response. Selecting 1,000 of 10,000 events measured 2.39 us p50 and 8.48 MiB peak RSS, versus 2.09 ms and 14.59 MiB for cloning the complete history.

The configured payload bound applies to the complete HTTP body before Axum deserializes JSON. Protected routes accept exactly one well-formed bearer Authorization header; duplicates fail closed.

Structured query validation streams JSON into a bounded counting writer. It therefore enforces the exact serialized-byte limit without retaining an encoded Vec<u8>, while the public payload_bytes() method remains compatible. The HTTP path validates once before the request crosses into 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 call CommandRequest::into_envelope, preserving V1 validation while moving the existing UTF-8 allocation into CommandEnvelope. The compatible to_envelope method remains available to 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.

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.

1.0.2-rc: coordinated routing reload

The 1.0.2-rc source candidate adds the opt-in ReloadableRuntimeHttpHost. A candidate must use a strictly newer generation on the same bound address and pass /v1/health before and after one atomic routing switch. Requests already accepted retain their original Router until completion; the old generation drains under a deadline. Failed health or drain restores the prior generation and closes failed-generation admission.

The owner retains at most one active and one retiring generation. A failed generation with requests blocks another reload until its final permit releases the Router. generation_snapshot reports active/retiring admission and in-flight counts without request data or an unbounded history. Cancelling after the switch synchronously restores the previous generation.

The active pointer is lock-free, deadlines are capped at 60 seconds and the snapshot contains only generation, in-flight, success, failure and rollback counters. A composition root may transfer an already bound TCP listener for bind-before-start validation. Address changes require a separate prepared listener generation and are not inferred.

This API is source status only. Do not infer that it is available from the stable 1.0.0 package shown above. See coordinated reload.

Maturity: stable strict HTTP V1 surface.