1#![doc = include_str!("../README.md")]
2
3use std::{
4 ops::Deref,
5 sync::{Mutex, MutexGuard},
6};
7
8use axum::Router;
9use once_cell::sync::Lazy;
10use serde::Serialize;
11use utoipa::openapi::Paths;
12
13#[cfg(feature = "derive")]
14extern crate axum_openapi3_derive;
15#[cfg(feature = "derive")]
17pub use axum_openapi3_derive::endpoint;
18
19pub use utoipa;
21
22pub static ENDPOINTS: std::sync::Mutex<Vec<utoipa::openapi::Paths>> = std::sync::Mutex::new(vec![]);
25
26pub trait AddRoute<S> {
28 fn add(
29 self,
30 r: (
31 &str,
32 axum::routing::MethodRouter<S, std::convert::Infallible>,
33 ),
34 ) -> Self;
35}
36
37impl<S: std::clone::Clone + std::marker::Send + std::marker::Sync + 'static> AddRoute<S>
38 for Router<S>
39{
40 fn add(
41 self,
42 r: (
43 &str,
44 axum::routing::MethodRouter<S, std::convert::Infallible>,
45 ),
46 ) -> Self {
47 self.route(r.0, r.1)
48 }
49}
50
51static OPENAPI_BUILT: Lazy<Mutex<Option<utoipa::openapi::OpenApi>>> =
52 Lazy::new(|| Mutex::new(None));
53
54pub fn reset_openapi() {
56 let mut endpoints = ENDPOINTS.lock().unwrap();
57 *endpoints = vec![];
58 *OPENAPI_BUILT.lock().unwrap() = None;
59}
60
61pub struct OpenApiWrapper<'a> {
64 guard: MutexGuard<'a, Option<utoipa::openapi::OpenApi>>,
65}
66impl Deref for OpenApiWrapper<'_> {
67 type Target = utoipa::openapi::OpenApi;
68
69 fn deref(&self) -> &Self::Target {
70 self.guard.as_ref().unwrap()
71 }
72}
73
74impl Serialize for OpenApiWrapper<'_> {
75 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76 where
77 S: serde::Serializer,
78 {
79 self.guard.as_ref().unwrap().serialize(serializer)
80 }
81}
82
83pub fn build_openapi<'openapi, F>(f: F) -> OpenApiWrapper<'openapi>
88where
89 F: Fn() -> utoipa::openapi::OpenApiBuilder,
90{
91 let mut openapi = OPENAPI_BUILT.lock().unwrap();
92 if openapi.is_none() {
93 let mut endpoints = ENDPOINTS.lock().unwrap();
94
95 let paths = endpoints.drain(..).fold(Paths::default(), |mut acc, x| {
96 acc.merge(x);
97 acc
98 });
99 let openapi_builder = f().paths(paths);
100
101 *openapi = Some(openapi_builder.build());
102 }
103
104 OpenApiWrapper { guard: openapi }
105}