umbral_core/web.rs
1//! The web layer. At M0 this is a thin re-export of axum's primitives.
2//!
3//! Later milestones will add umbral-specific wrappers (named routes for
4//! `reverse()`, middleware registration through the Plugin contract, etc.)
5//! while keeping the underlying axum API accessible.
6
7pub mod multipart;
8pub mod streaming;
9
10pub use axum::Router;
11pub use axum::extract::{Form, Json, Path, Query, Request};
12pub use axum::http::{HeaderMap, StatusCode, header};
13pub use axum::response::{Html, IntoResponse, Json as JsonResponse, Redirect, Response};
14pub use axum::routing::{delete, get, head, options, patch, post, put};
15pub use streaming::StreamingResponse;
16
17use std::sync::OnceLock;
18
19/// Process-wide API base path, published by the REST plugin during build
20/// (before router assembly) so other plugins — notably umbral-auth — can
21/// mount their JSON routes under the same prefix without a Cargo dependency
22/// on umbral-rest. Defaults to "/api" when no REST plugin set it.
23static API_BASE: OnceLock<String> = OnceLock::new();
24
25/// Read the configured API base path. Returns "/api" until [`set_api_base`]
26/// runs. Trailing slashes are not normalized here — callers append "/auth"
27/// etc. directly, and the REST plugin publishes its own normalized base.
28pub fn api_base() -> String {
29 API_BASE
30 .get()
31 .cloned()
32 .unwrap_or_else(|| "/api".to_string())
33}
34
35/// Publish the API base path. First call wins (mirrors the REST plugin's
36/// own `CONFIG` OnceLock); subsequent calls are ignored. The REST plugin
37/// calls this in an early build phase.
38pub fn set_api_base(base: impl Into<String>) {
39 let _ = API_BASE.set(base.into());
40}
41
42#[cfg(test)]
43mod api_base_tests {
44 use super::*;
45 #[test]
46 fn api_base_defaults_to_api_then_takes_first_set() {
47 // Default before any set.
48 assert_eq!(api_base(), "/api");
49 set_api_base("/v2");
50 assert_eq!(api_base(), "/v2");
51 // First-set-wins: a later set is ignored.
52 set_api_base("/v3");
53 assert_eq!(api_base(), "/v2");
54 }
55}