diff options
| author | tv <tv@krebsco.de> | 2026-10-26 21:43:42 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-26 21:43:42 +0100 |
| commit | 3374b029bea44fed6ad5a46a7a05c269ce61af58 (patch) | |
| tree | ca9eba49e886c9dcd4416c4fe7790ca34f07f376 /src/api/mod.rs | |
| parent | 137b1547f847ff2402ea9e634b64ee2196a75075 (diff) | |
replace utoipa by static openapi.yaml
Diffstat (limited to 'src/api/mod.rs')
| -rw-r--r-- | src/api/mod.rs | 59 |
1 files changed, 16 insertions, 43 deletions
diff --git a/src/api/mod.rs b/src/api/mod.rs index bf7b06b..20237e1 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,4 +1,4 @@ -//! HTTP API: router, OpenAPI document and shared response helpers. +//! HTTP API: router, the API description and shared response helpers. pub(crate) mod auth; mod debug; @@ -24,7 +24,6 @@ use axum::{ use serde_json::{Value as JsonValue, json}; use sha2::{Digest, Sha256}; use tracing::{error, warn}; -use utoipa::OpenApi; use utoipa_swagger_ui::SwaggerUi; use crate::api::auth::{AuthState, AuthenticatedUser, basic_auth}; @@ -32,8 +31,8 @@ use crate::document::meta; use crate::document::store::StoreError; use crate::state::AppState; -/// Builds the complete HTTP router. Everything except Swagger, `/health` and `/ready` is -/// authenticated. +/// Builds the complete HTTP router. Everything except the API description (`/swagger-ui`, +/// `/openapi.yaml`), `/health` and `/ready` is authenticated. pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) -> Router { let mut api: Router<AppState> = Router::new() .route("/store", get(store::get_store_root)) @@ -65,7 +64,11 @@ pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) -> } api.layer(middleware::from_fn_with_state(auth_state, basic_auth)) - .merge(SwaggerUi::new("/swagger-ui").url("/openapi.json", ApiDoc::openapi())) + // The hand-written spec (`docs/openapi.yaml`), and the Swagger UI showing it. + .merge( + SwaggerUi::new("/swagger-ui").config(utoipa_swagger_ui::Config::from("/openapi.yaml")), + ) + .route("/openapi.yaml", get(openapi_spec)) .route("/health", get(health::health)) .route("/ready", get(health::ready)) // Outermost, so authentication failures get the error body too. @@ -125,6 +128,14 @@ async fn json_errors(request: Request, next: Next) -> Response { Response::from_parts(parts, Body::from(body)) } +/// `GET /openapi.yaml`: the API description (`docs/openapi.yaml`, built in). +async fn openapi_spec() -> impl IntoResponse { + ( + [(CONTENT_TYPE, HeaderValue::from_static("application/yaml"))], + include_str!("../../docs/openapi.yaml"), + ) +} + /// `GET /admin/config`: the effective configuration with each value's source; /// imported values are left out. async fn get_config(State(state): State<AppState>) -> Json<JsonValue> { @@ -231,41 +242,3 @@ fn response_for_value( Ok(response) } - -// --- openapi spec ------------------------------------------------------------ -// TODO spec is mostly out of sync - -#[derive(OpenApi)] -#[openapi( - paths( - store::get_store_root, - store::get_store_entry, - store::put_store_entry, - store::delete_store_entry, - peers::list_peers, - peers::delete_peer, - ), - components( - schemas( - peers::PeerStatus, - peers::PeerListResponse, - peers::PeerLivenessStatus, - peers::EpochInfo, - crate::transport::traffic::PeerTraffic, - crate::transport::traffic::ByKind, - crate::transport::traffic::Counter, - crate::state::Incidents, - peers::ThroughputInfo, - ) - ), - tags( - (name = "Store", description = "Key-value store operations"), - (name = "Peers", description = "Peer discovery and retirement") - ), - info( - title = "Automerge Replication API", - version = "1.0.0", - description = "HTTP API for a replicated Automerge key-value store" - ) -)] -struct ApiDoc; |
