Skip to main content

loco_openapi/
utils.rs

1use std::sync::OnceLock;
2
3use axum::{response::Response, routing::get, Router as AxumRouter};
4use utoipa::openapi::OpenApi;
5
6use loco_rs::{controller::format, Result};
7
8static OPENAPI_SPEC: OnceLock<OpenApi> = OnceLock::new();
9
10pub fn set_openapi_spec(api: OpenApi) -> &'static OpenApi {
11    OPENAPI_SPEC.get_or_init(|| api)
12}
13
14/// # Panics
15///
16/// Will panic if `OpenAPI` spec fails to build
17pub fn get_openapi_spec() -> &'static OpenApi {
18    OPENAPI_SPEC.get().unwrap()
19}
20
21/// Axum handler that returns the `OpenAPI` spec as JSON
22///
23/// # Errors
24/// Currently this function doesn't return any error. this is for feature
25/// functionality
26pub async fn openapi_spec_json() -> Result<Response> {
27    format::json(get_openapi_spec())
28}
29
30/// Axum handler that returns the `OpenAPI` spec as YAML
31///
32/// # Errors
33/// Currently this function doesn't return any error. this is for feature
34/// functionality
35pub async fn openapi_spec_yaml() -> Result<Response> {
36    let yaml = get_openapi_spec()
37        .to_yaml()
38        .map_err(|e| loco_rs::Error::Any(Box::new(e)))?;
39    format::yaml(&yaml)
40}
41
42/// Adds the `OpenAPI` endpoints the app router
43pub fn add_openapi_endpoints<T>(
44    mut app: AxumRouter<T>,
45    json_url: &Option<String>,
46    yaml_url: &Option<String>,
47) -> AxumRouter<T>
48where
49    T: Clone + Send + Sync + 'static,
50{
51    if let Some(json_url) = json_url {
52        app = app.route(json_url, get(openapi_spec_json));
53    }
54    if let Some(yaml_url) = yaml_url {
55        app = app.route(yaml_url, get(openapi_spec_yaml));
56    }
57    app
58}