From 7752ae94513a335d97d984cb7274963775643a32 Mon Sep 17 00:00:00 2001 From: YISH Date: Wed, 15 Jan 2025 20:31:04 +0800 Subject: [PATCH] Add HTTP method macros to simplify path attribute macro - Added `get`, `post`, `put`, `delete`, `options`, `head`, `patch`, `trace`, and `any` macros to simplify the `path` attribute configuration. - These macros allow developers to define routes more concisely and improve code readability. --- utoipa-axum/src/lib.rs | 28 ++++-- utoipa-gen/src/lib.rs | 207 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+), 9 deletions(-) diff --git a/utoipa-axum/src/lib.rs b/utoipa-axum/src/lib.rs index e4aff514..cc0f1e4a 100644 --- a/utoipa-axum/src/lib.rs +++ b/utoipa-axum/src/lib.rs @@ -202,37 +202,47 @@ mod tests { use tower::util::ServiceExt; use utoipa::openapi::{Content, OpenApi, Ref, ResponseBuilder}; use utoipa::PartialSchema; + use utoipa::{delete, get, post}; - #[utoipa::path(get, path = "/")] + // #[utoipa::path(get, path = "/")] + #[get("/")] async fn root() {} // --- user - #[utoipa::path(get, path = "/")] + // #[utoipa::path(get, path = "/")] + #[get("/")] async fn get_user() {} - #[utoipa::path(post, path = "/")] + // #[utoipa::path(post, path = "/")] + #[post("/")] async fn post_user() {} - #[utoipa::path(delete, path = "/")] + // #[utoipa::path(delete, path = "/")] + #[delete("/")] async fn delete_user() {} - #[utoipa::path(get, path = "/search")] + // #[utoipa::path(get, path = "/search")] + #[get("/search")] async fn search_user() {} // --- customer - #[utoipa::path(get, path = "/")] + // #[utoipa::path(get, path = "/")] + #[get("/")] async fn get_customer() {} - #[utoipa::path(post, path = "/")] + // #[utoipa::path(post, path = "/")] + #[post("/")] async fn post_customer() {} - #[utoipa::path(delete, path = "/")] + // #[utoipa::path(delete, path = "/")] + #[delete("/")] async fn delete_customer() {} // test that with state handler compiles - #[utoipa::path(get, path = "/search")] + // #[utoipa::path(get, path = "/search")] + #[get("/search")] async fn search_customer(State(_s): State) {} #[test] diff --git a/utoipa-gen/src/lib.rs b/utoipa-gen/src/lib.rs index b57f8de2..035c0db8 100644 --- a/utoipa-gen/src/lib.rs +++ b/utoipa-gen/src/lib.rs @@ -1957,6 +1957,213 @@ pub fn path(attr: TokenStream, item: TokenStream) -> TokenStream { handler.to_token_stream().into() } +/// HttpMethod Get +/// +/// ```rust +/// use utoipa::get; +/// +/// #[get("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(get, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("get, path={}", attr.to_string()).parse().unwrap(), + item, + ) +} + +/// HttpMethod Post +/// +/// ```rust +/// use utoipa::post; +/// +/// #[post("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(post, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("post, path={}", attr.to_string()).parse().unwrap(), + item, + ) +} + +/// HttpMethod Put +/// +/// ```rust +/// use utoipa::put; +/// +/// #[put("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(put, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("put, path={}", attr.to_string()).parse().unwrap(), + item, + ) +} + +/// HttpMethod Delete +/// +/// ```rust +/// use utoipa::delete; +/// +/// #[delete("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(delete, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("delete, path={}", attr.to_string()) + .parse() + .unwrap(), + item, + ) +} + +/// HttpMethod Options +/// +/// ```rust +/// use utoipa::options; +/// +/// #[options("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(options, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn options(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("options, path={}", attr.to_string()) + .parse() + .unwrap(), + item, + ) +} + +/// HttpMethod Head +/// +/// ```rust +/// use utoipa::head; +/// +/// #[head("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(head, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn head(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("head, path={}", attr.to_string()).parse().unwrap(), + item, + ) +} + +/// HttpMethod Patch +/// +/// ```rust +/// use utoipa::patch; +/// +/// #[patch("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(patch, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn patch(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("patch, path={}", attr.to_string()).parse().unwrap(), + item, + ) +} + +/// HttpMethod Trace +/// +/// ```rust +/// use utoipa::trace; +/// +/// #[trace("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(trace, path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn trace(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!("trace, path={}", attr.to_string()).parse().unwrap(), + item, + ) +} + +/// HttpMethod Any +/// +/// ```rust +/// use utoipa::any; +/// +/// #[any("/")] +/// async fn root() {} +/// +/// ``` +/// Equivalent to: +/// ```rust +/// #[utoipa::path(method(get,post,put,delete,options,head,patch,trace), path = "/")] +/// async fn root() {} +/// ``` +#[proc_macro_attribute] +pub fn any(attr: TokenStream, item: TokenStream) -> TokenStream { + path( + format!( + "method(get,post,put,delete,options,head,patch,trace), path={}", + attr.to_string() + ) + .parse() + .unwrap(), + item, + ) +} + #[proc_macro_derive(OpenApi, attributes(openapi))] /// Generate OpenApi base object with defaults from /// project settings.