use utoipa::Modify; use utoipa::openapi::OpenApi as OpenApiValue; /// Prepends a fixed path prefix to every entry in `OpenApi::paths`. /// /// Used by the `openapi_modify_prefix!` macro; also usable directly via /// `#[openapi(modifiers(&PrefixModifier { prefix: ... }))]`. pub struct PrefixModifier { pub prefix: String, } impl Modify for PrefixModifier { fn modify(&self, openapi: &mut OpenApiValue) { let paths = std::mem::take(&mut openapi.paths.paths); for (path, item) in paths { let new_path = if path.starts_with('/') { format!("{}{}", self.prefix, path) } else { format!("{}/{}", self.prefix, path) }; openapi.paths.paths.insert(new_path, item); } } } /// Build the OpenAPI spec for `$doc` and prepend `$prefix` to every path. /// /// Returns the modified `utoipa::openapi::OpenApi` value. /// /// # Example /// ```ignore /// use export::openapi_modify_prefix; /// use auth::handler::AuthApiDoc; /// let spec = openapi_modify_prefix!(AuthApiDoc, "/api/v1"); /// ``` #[macro_export] macro_rules! openapi_modify_prefix { ($doc:ty, $prefix:expr) => {{ let mut __spec = <$doc as ::utoipa::OpenApi>::openapi(); let __modif = $crate::openapi::PrefixModifier { prefix: ($prefix).to_string(), }; ::utoipa::Modify::modify(&__modif, &mut __spec); __spec }}; } /// Merge multiple OpenAPI docs into one via `OpenApi::merge`, left-to-right. /// /// Returns the merged `utoipa::openapi::OpenApi` value. Per `OpenApi::merge`, /// `info`, `openapi`, `external_docs`, and `schema` from later docs are dropped /// — the first doc's values win. /// /// # Example /// ```ignore /// use export::openapi_concat; /// use auth::handler::AuthApiDoc; /// use user::handler::UserApiDoc; /// let all = openapi_concat!(AuthApiDoc, UserApiDoc); /// ``` #[macro_export] macro_rules! openapi_concat { ($first:ty $(, $rest:ty)* $(,)?) => {{ let mut __acc = <$first as ::utoipa::OpenApi>::openapi(); $( __acc.merge(<$rest as ::utoipa::OpenApi>::openapi()); )* __acc }}; }