4e3e4e3
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
}};
}