From 8895926f73e361047ad01e0aeff4fce443739275 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Wed, 8 Dec 2021 19:37:18 +0100 Subject: [PATCH] Support customizing the request body type in `#[debug_handler]` (#595) --- axum-debug/CHANGELOG.md | 4 +- axum-debug/src/lib.rs | 53 ++++++++++++++++--- axum-debug/tests/fail/attrs.stderr | 5 -- .../tests/fail/{attrs.rs => invalid_attrs.rs} | 0 axum-debug/tests/fail/invalid_attrs.stderr | 5 ++ .../tests/pass/different_request_body_type.rs | 10 ++++ axum-debug/tests/pass/returns_self.rs | 5 +- 7 files changed, 64 insertions(+), 18 deletions(-) delete mode 100644 axum-debug/tests/fail/attrs.stderr rename axum-debug/tests/fail/{attrs.rs => invalid_attrs.rs} (100%) create mode 100644 axum-debug/tests/fail/invalid_attrs.stderr create mode 100644 axum-debug/tests/pass/different_request_body_type.rs diff --git a/axum-debug/CHANGELOG.md b/axum-debug/CHANGELOG.md index 90f4089e..cd577601 100644 --- a/axum-debug/CHANGELOG.md +++ b/axum-debug/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased -- None. +- Support checking `FromRequest` bounds for extractors whose request body is something else than + `axum::body::Body`. Use `#[debug_handler(body = YourBodyType)]` to use a different request body + type. # 0.3.1 (06. December 2021) diff --git a/axum-debug/src/lib.rs b/axum-debug/src/lib.rs index 8fe522c4..2c58365d 100644 --- a/axum-debug/src/lib.rs +++ b/axum-debug/src/lib.rs @@ -73,6 +73,22 @@ //! } //! ``` //! +//! # Changing request body type +//! +//! By default `#[debug_handler]` assumes your request body type is `axum::body::Body`. This will +//! work for most extractors but, for example, it wont work for `Request`, +//! which only implements `FromRequest` and _not_ `FromRequest`. +//! +//! To work around that the request body type can be customized like so: +//! +//! ```rust +//! use axum::{body::BoxBody, http::Request}; +//! # use axum_debug::debug_handler; +//! +//! #[debug_handler(body = BoxBody)] +//! async fn handler(request: Request) {} +//! ``` +//! //! # Performance //! //! Macros in this crate have no effect when using release profile. (eg. `cargo build --release`) @@ -125,6 +141,8 @@ use proc_macro::TokenStream; /// Generates better error messages when applied to a handler function. +/// +/// See the [module docs](self) for more details. #[proc_macro_attribute] pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream { #[cfg(not(debug_assertions))] @@ -138,7 +156,7 @@ pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream { mod debug_handler { use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned}; - use syn::{parse::Parse, spanned::Spanned, FnArg, ItemFn}; + use syn::{parse::Parse, spanned::Spanned, FnArg, ItemFn, Token, Type}; pub(crate) fn expand( attr: proc_macro::TokenStream, @@ -151,12 +169,13 @@ mod debug_handler { } pub(crate) fn try_expand(attr: TokenStream, input: TokenStream) -> syn::Result { - syn::parse2::(attr)?; + let attr = syn::parse2::(attr)?; let item_fn = syn::parse2::(input.clone())?; check_extractor_count(&item_fn)?; - let check_inputs_impls_from_request = check_inputs_impls_from_request(&item_fn); + let check_inputs_impls_from_request = + check_inputs_impls_from_request(&item_fn, &attr.body_ty); let check_output_impls_into_response = check_output_impls_into_response(&item_fn); let check_future_send = check_future_send(&item_fn); @@ -170,11 +189,29 @@ mod debug_handler { Ok(tokens) } - struct Attrs; + struct Attrs { + body_ty: Type, + } impl Parse for Attrs { - fn parse(_input: syn::parse::ParseStream) -> syn::Result { - Ok(Self) + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let mut body_ty = None; + + while !input.is_empty() { + let ident = input.parse::()?; + if ident == "body" { + input.parse::()?; + body_ty = Some(input.parse()?); + } else { + return Err(syn::Error::new_spanned(ident, "unknown argument")); + } + + let _ = input.parse::(); + } + + let body_ty = body_ty.unwrap_or_else(|| syn::parse_quote!(axum::body::Body)); + + Ok(Self { body_ty }) } } @@ -193,7 +230,7 @@ mod debug_handler { } } - fn check_inputs_impls_from_request(item_fn: &ItemFn) -> TokenStream { + fn check_inputs_impls_from_request(item_fn: &ItemFn, body_ty: &Type) -> TokenStream { if !item_fn.sig.generics.params.is_empty() { return syn::Error::new_spanned( &item_fn.sig.generics, @@ -237,7 +274,7 @@ mod debug_handler { #[allow(warnings)] fn #name() where - #ty: ::axum::extract::FromRequest<::axum::body::Body> + Send, + #ty: ::axum::extract::FromRequest<#body_ty> + Send, {} } }) diff --git a/axum-debug/tests/fail/attrs.stderr b/axum-debug/tests/fail/attrs.stderr deleted file mode 100644 index b01bf728..00000000 --- a/axum-debug/tests/fail/attrs.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: unexpected token - --> tests/fail/attrs.rs:3:17 - | -3 | #[debug_handler(foo)] - | ^^^ diff --git a/axum-debug/tests/fail/attrs.rs b/axum-debug/tests/fail/invalid_attrs.rs similarity index 100% rename from axum-debug/tests/fail/attrs.rs rename to axum-debug/tests/fail/invalid_attrs.rs diff --git a/axum-debug/tests/fail/invalid_attrs.stderr b/axum-debug/tests/fail/invalid_attrs.stderr new file mode 100644 index 00000000..976981c7 --- /dev/null +++ b/axum-debug/tests/fail/invalid_attrs.stderr @@ -0,0 +1,5 @@ +error: unknown argument + --> tests/fail/invalid_attrs.rs:3:17 + | +3 | #[debug_handler(foo)] + | ^^^ diff --git a/axum-debug/tests/pass/different_request_body_type.rs b/axum-debug/tests/pass/different_request_body_type.rs new file mode 100644 index 00000000..0a2467d8 --- /dev/null +++ b/axum-debug/tests/pass/different_request_body_type.rs @@ -0,0 +1,10 @@ +use axum::{body::BoxBody, http::Request}; +use axum_debug::debug_handler; + +#[debug_handler(body = BoxBody)] +async fn handler(_: Request) {} + +#[debug_handler(body = axum::body::BoxBody,)] +async fn handler_with_trailing_comma_and_type_path(_: Request) {} + +fn main() {} diff --git a/axum-debug/tests/pass/returns_self.rs b/axum-debug/tests/pass/returns_self.rs index cff39c85..9c9c09a2 100644 --- a/axum-debug/tests/pass/returns_self.rs +++ b/axum-debug/tests/pass/returns_self.rs @@ -1,7 +1,4 @@ -use axum::{ - body::BoxBody, - response::{IntoResponse, Response}, -}; +use axum::response::{IntoResponse, Response}; use axum_debug::debug_handler; struct A;