From b0f5d8d3f15be478cc00a5ab5ae6c66759a49bd1 Mon Sep 17 00:00:00 2001 From: Maxime Borges Date: Sun, 17 Dec 2023 15:54:36 +0100 Subject: [PATCH] Add get_nested_endpoints_and_docs macro and update example --- examples/nested/src/api/mod.rs | 29 +++------------ rocket-okapi/src/lib.rs | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/examples/nested/src/api/mod.rs b/examples/nested/src/api/mod.rs index 88195462..76fbfd95 100644 --- a/examples/nested/src/api/mod.rs +++ b/examples/nested/src/api/mod.rs @@ -2,30 +2,11 @@ mod post; mod message; use rocket::Route; -use rocket_okapi::{okapi::openapi3::OpenApi, settings::OpenApiSettings}; +use rocket_okapi::{okapi::openapi3::OpenApi, settings::OpenApiSettings, get_nested_endpoints_and_docs}; pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec, OpenApi) { - let mut routes = vec![]; - let mut openapi_list: Vec<(_, rocket_okapi::okapi::openapi3::OpenApi)> = Vec::new(); - - [ - ("/posts", post::get_routes_and_docs(settings)), - ("/message", message::get_routes_and_docs(settings)), - ] - .into_iter() - .for_each(|(path, (new_routes, openapi))| { - let new_routes = new_routes - .into_iter() - .map(|r: Route| r.map_base(|base| format!("{}{}", path, base)).unwrap()) - .collect::>(); - routes.extend(new_routes); - openapi_list.push((path, openapi)); - }); - - let openapi_docs = match rocket_okapi::okapi::merge::marge_spec_list(&openapi_list) { - Ok(docs) => docs, - Err(err) => panic!("Could not merge OpenAPI spec: {}", err), - }; - - (routes, openapi_docs) + get_nested_endpoints_and_docs! { + "/posts" => post::get_routes_and_docs(settings), + "/message" => message::get_routes_and_docs(settings), + } } diff --git a/rocket-okapi/src/lib.rs b/rocket-okapi/src/lib.rs index b119dcc1..2c9e56ab 100644 --- a/rocket-okapi/src/lib.rs +++ b/rocket-okapi/src/lib.rs @@ -182,6 +182,74 @@ macro_rules! mount_endpoints_and_merged_docs { }}; } + + +/// Get and merge nested endpoints and OpenAPI documentation. +/// +/// This macro enables to split endpoints definition in smaller pieces to make code look +/// cleaner and improves readability for bigger codebases. +/// +/// The macro expects the following arguments: +/// - List of (0 or more): +/// - path: `&str`, `String` or [`Uri`](rocket::http::uri::Uri). +/// Anything accepted by `mount()` (`base_path` should not be included). +/// - `=>`: divider +/// - route_and_docs: `(Vec, OpenApi)` +/// +/// Example: +/// ```rust,ignore +/// let settings = OpenApiSettings::default(); +/// let custom_route_spec = (vec![], custom_spec()); +/// mount_endpoints_and_merged_docs! { +/// building_rocket, "/v1".to_owned(), settings, +/// "/" => custom_route_spec, +/// "/api" => api::get_routes_and_docs(), +/// }; +/// +/// mod api { +/// pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec, OpenApi) { +/// get_nested_endpoints_and_docs! { +/// "/posts" => post::get_routes_and_docs(settings), +/// "/message" => message::get_routes_and_docs(settings), +/// } +/// } +/// mod posts { +/// pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec, OpenApi) { +/// openapi_get_routes_spec![settings: create_post, get_post] +/// } +/// } +/// mod messages { +/// pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec, OpenApi) { +/// openapi_get_routes_spec![settings: create_message, get_message] +/// } +/// } +/// } +/// ``` +/// +#[macro_export] +macro_rules! get_nested_endpoints_and_docs { + ($($path_prefix:expr => $route_and_docs:expr),* $(,)*) => {{ + let mut routes = Vec::new(); + let mut openapi_specs = rocket_okapi::okapi::openapi3::OpenApi::new(); + + $({ + let (new_routes, new_specs) = $route_and_docs; + // Prepend the path prefix to all routes + let new_routes = new_routes + .into_iter() + .map(|r: Route| r.map_base(|base| format!("{}{}", $path_prefix, base)).unwrap()) + .collect::>(); + routes.extend(new_routes); + // Merge OpenAPI specs + if let Err(err) = rocket_okapi::okapi::merge::merge_specs(&mut openapi_specs, &$path_prefix, &new_specs) { + panic!("Failed to merge specs: {}", err) + } + })* + + (routes, openapi_specs) + }}; +} + /// A replacement macro for `rocket::routes`. This also takes a optional settings object. /// /// The key differences are that this macro will add an additional element to the