summaryrefslogtreecommitdiffstats
path: root/src/api/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/mod.rs')
-rw-r--r--src/api/mod.rs59
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;