From 7d88bd3a6699a548a47f9742edb612a8f8f88234 Mon Sep 17 00:00:00 2001 From: David Pedersen <david.pdrsn@gmail.com> Date: Mon, 16 May 2022 15:11:40 +0100 Subject: [PATCH] Check for multiple body extractors in `debug_handler` (#1036) * Check for multiple body extractors in `debug_handler` * changelog link --- axum-macros/CHANGELOG.md | 2 ++ axum-macros/src/debug_handler.rs | 28 +++++++++++++++ .../fail/multiple_body_extractors.rs | 7 ++++ .../fail/multiple_body_extractors.stderr | 11 ++++++ .../debug_handler/fail/too_many_extractors.rs | 35 ++++++++++--------- .../fail/too_many_extractors.stderr | 16 ++++----- .../debug_handler/pass/multiple_extractors.rs | 3 +- 7 files changed, 76 insertions(+), 26 deletions(-) create mode 100644 axum-macros/tests/debug_handler/fail/multiple_body_extractors.rs create mode 100644 axum-macros/tests/debug_handler/fail/multiple_body_extractors.stderr diff --git a/axum-macros/CHANGELOG.md b/axum-macros/CHANGELOG.md index c1b438d9..bf1d8656 100644 --- a/axum-macros/CHANGELOG.md +++ b/axum-macros/CHANGELOG.md @@ -9,8 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **added:** In `debug_handler`, check if `Request` is used as non-final extractor ([#1035]) - **added:** In `debug_handler`, check if multiple `Path` extractors are used ([#1035]) +- **added:** In `debug_handler`, check if multiple body extractors are used ([#1036]) [#1035]: https://github.com/tokio-rs/axum/pull/1035 +[#1036]: https://github.com/tokio-rs/axum/pull/1036 # 0.2.1 (10. May, 2022) diff --git a/axum-macros/src/debug_handler.rs b/axum-macros/src/debug_handler.rs index 3404cda6..7945e8bb 100644 --- a/axum-macros/src/debug_handler.rs +++ b/axum-macros/src/debug_handler.rs @@ -6,6 +6,7 @@ pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> TokenStream { let check_extractor_count = check_extractor_count(&item_fn); let check_request_last_extractor = check_request_last_extractor(&item_fn); let check_path_extractor = check_path_extractor(&item_fn); + let check_multiple_body_extractors = check_multiple_body_extractors(&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); @@ -16,6 +17,7 @@ pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> TokenStream { #check_extractor_count #check_request_last_extractor #check_path_extractor + #check_multiple_body_extractors #check_inputs_impls_from_request #check_output_impls_into_response #check_future_send @@ -124,6 +126,32 @@ fn check_path_extractor(item_fn: &ItemFn) -> TokenStream { } } +fn check_multiple_body_extractors(item_fn: &ItemFn) -> TokenStream { + let body_extractors = extractor_idents(item_fn) + .filter(|(_, _, ident)| { + *ident == "String" + || *ident == "Bytes" + || *ident == "Json" + || *ident == "RawBody" + || *ident == "BodyStream" + || *ident == "Multipart" + || *ident == "Request" + }) + .collect::<Vec<_>>(); + + if body_extractors.len() > 1 { + body_extractors + .into_iter() + .map(|(_, arg, _)| { + syn::Error::new_spanned(arg, "Only one body extractor can be applied") + .to_compile_error() + }) + .collect() + } else { + quote! {} + } +} + 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( diff --git a/axum-macros/tests/debug_handler/fail/multiple_body_extractors.rs b/axum-macros/tests/debug_handler/fail/multiple_body_extractors.rs new file mode 100644 index 00000000..875c7540 --- /dev/null +++ b/axum-macros/tests/debug_handler/fail/multiple_body_extractors.rs @@ -0,0 +1,7 @@ +use axum_macros::debug_handler; +use axum::body::Bytes; + +#[debug_handler] +async fn handler(_: String, _: Bytes) {} + +fn main() {} diff --git a/axum-macros/tests/debug_handler/fail/multiple_body_extractors.stderr b/axum-macros/tests/debug_handler/fail/multiple_body_extractors.stderr new file mode 100644 index 00000000..098f3675 --- /dev/null +++ b/axum-macros/tests/debug_handler/fail/multiple_body_extractors.stderr @@ -0,0 +1,11 @@ +error: Only one body extractor can be applied + --> tests/debug_handler/fail/multiple_body_extractors.rs:5:18 + | +5 | async fn handler(_: String, _: Bytes) {} + | ^^^^^^^^^ + +error: Only one body extractor can be applied + --> tests/debug_handler/fail/multiple_body_extractors.rs:5:29 + | +5 | async fn handler(_: String, _: Bytes) {} + | ^^^^^^^^ diff --git a/axum-macros/tests/debug_handler/fail/too_many_extractors.rs b/axum-macros/tests/debug_handler/fail/too_many_extractors.rs index d24fdcbb..d9317bf9 100644 --- a/axum-macros/tests/debug_handler/fail/too_many_extractors.rs +++ b/axum-macros/tests/debug_handler/fail/too_many_extractors.rs @@ -1,24 +1,25 @@ use axum_macros::debug_handler; +use axum::http::Uri; #[debug_handler] async fn handler( - e1: String, - e2: String, - e3: String, - e4: String, - e5: String, - e6: String, - e7: String, - e8: String, - e9: String, - e10: String, - e11: String, - e12: String, - e13: String, - e14: String, - e15: String, - e16: String, - e17: String, + e1: Uri, + e2: Uri, + e3: Uri, + e4: Uri, + e5: Uri, + e6: Uri, + e7: Uri, + e8: Uri, + e9: Uri, + e10: Uri, + e11: Uri, + e12: Uri, + e13: Uri, + e14: Uri, + e15: Uri, + e16: Uri, + e17: Uri, ) {} fn main() {} diff --git a/axum-macros/tests/debug_handler/fail/too_many_extractors.stderr b/axum-macros/tests/debug_handler/fail/too_many_extractors.stderr index a1afce89..0ba46212 100644 --- a/axum-macros/tests/debug_handler/fail/too_many_extractors.stderr +++ b/axum-macros/tests/debug_handler/fail/too_many_extractors.stderr @@ -1,11 +1,11 @@ error: Handlers cannot take more than 16 arguments. Use `(a, b): (ExtractorA, ExtractorA)` to further nest extractors - --> tests/debug_handler/fail/too_many_extractors.rs:5:5 + --> tests/debug_handler/fail/too_many_extractors.rs:6:5 | -5 | / e1: String, -6 | | e2: String, -7 | | e3: String, -8 | | e4: String, +6 | / e1: Uri, +7 | | e2: Uri, +8 | | e3: Uri, +9 | | e4: Uri, ... | -20 | | e16: String, -21 | | e17: String, - | |________________^ +21 | | e16: Uri, +22 | | e17: Uri, + | |_____________^ diff --git a/axum-macros/tests/debug_handler/pass/multiple_extractors.rs b/axum-macros/tests/debug_handler/pass/multiple_extractors.rs index 5c7ab044..6cc05b51 100644 --- a/axum-macros/tests/debug_handler/pass/multiple_extractors.rs +++ b/axum-macros/tests/debug_handler/pass/multiple_extractors.rs @@ -1,6 +1,7 @@ use axum_macros::debug_handler; +use axum::http::{Method, Uri}; #[debug_handler] -async fn handler(_one: String, _two: String, _three: String) {} +async fn handler(_one: Method, _two: Uri, _three: String) {} fn main() {}