Skip to main content

assay_workflow/api/
public.rs

1//! Public `/api/v1/*` endpoints — callable without authentication even when
2//! the server is configured with `--auth-issuer` or `--auth-api-key`.
3//!
4//! Two routes live here today:
5//!
6//!   - `GET /api/v1/health`  — static liveness/readiness probe. Used by
7//!     Kubernetes kubelet, load balancers, and any in-cluster monitor
8//!     without a bearer token.
9//!
10//!   - `GET /api/v1/version` — engine version + build profile. Used by
11//!     the CLI, dashboard, and third-party monitors to identify the
12//!     running build. Cheap, static, no sensitive data.
13//!
14//! Both are wired outside the auth middleware layer in `api/mod.rs`. The
15//! handlers live here (rather than being inlined) so Utoipa can tag and
16//! document them under a single `public` module.
17use std::sync::Arc;
18
19use axum::extract::State;
20use axum::routing::get;
21use axum::{Json, Router};
22use serde::Serialize;
23use utoipa::ToSchema;
24
25use crate::api::AppState;
26use crate::store::WorkflowStore;
27
28pub fn router<S: WorkflowStore + 'static>() -> Router<Arc<AppState<S>>> {
29    Router::new()
30        .route("/health", get(health_check))
31        .route("/version", get(version))
32}
33
34#[utoipa::path(
35    get, path = "/api/v1/health",
36    tag = "public",
37    responses((status = 200, description = "Engine health — always unauthenticated")),
38)]
39pub async fn health_check() -> Json<serde_json::Value> {
40    Json(serde_json::json!({
41        "status": "ok",
42        "service": "assay-workflow",
43    }))
44}
45
46#[derive(Serialize, ToSchema)]
47pub struct VersionInfo {
48    /// Semver of the user-facing binary (or the `assay-workflow` crate when
49    /// no embedder version was supplied). Matches `assay --version`.
50    pub version: &'static str,
51    /// `release` or `debug`.
52    pub build_profile: &'static str,
53}
54
55#[utoipa::path(
56    get, path = "/api/v1/version",
57    tag = "public",
58    responses((status = 200, description = "Engine version info", body = VersionInfo)),
59)]
60pub async fn version<S: WorkflowStore>(
61    State(state): State<Arc<AppState<S>>>,
62) -> Json<VersionInfo> {
63    let version = state
64        .binary_version
65        .unwrap_or(env!("CARGO_PKG_VERSION"));
66    Json(VersionInfo {
67        version,
68        build_profile: if cfg!(debug_assertions) {
69            "debug"
70        } else {
71            "release"
72        },
73    })
74}