mirror of
https://github.com/tokio-rs/axum.git
synced 2025-09-30 06:21:07 +00:00
Support customizing the request body type in #[debug_handler]
(#595)
This commit is contained in:
parent
4b85b227e1
commit
8895926f73
@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
# Unreleased
|
# 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)
|
# 0.3.1 (06. December 2021)
|
||||||
|
|
||||||
|
@ -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<axum::body::BoxBody>`,
|
||||||
|
//! which only implements `FromRequest<BoxBody>` and _not_ `FromRequest<Body>`.
|
||||||
|
//!
|
||||||
|
//! 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<BoxBody>) {}
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! # Performance
|
//! # Performance
|
||||||
//!
|
//!
|
||||||
//! Macros in this crate have no effect when using release profile. (eg. `cargo build --release`)
|
//! Macros in this crate have no effect when using release profile. (eg. `cargo build --release`)
|
||||||
@ -125,6 +141,8 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
/// Generates better error messages when applied to a handler function.
|
/// Generates better error messages when applied to a handler function.
|
||||||
|
///
|
||||||
|
/// See the [module docs](self) for more details.
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
@ -138,7 +156,7 @@ pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
mod debug_handler {
|
mod debug_handler {
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote, quote_spanned};
|
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(
|
pub(crate) fn expand(
|
||||||
attr: proc_macro::TokenStream,
|
attr: proc_macro::TokenStream,
|
||||||
@ -151,12 +169,13 @@ mod debug_handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn try_expand(attr: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
|
pub(crate) fn try_expand(attr: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
|
||||||
syn::parse2::<Attrs>(attr)?;
|
let attr = syn::parse2::<Attrs>(attr)?;
|
||||||
let item_fn = syn::parse2::<ItemFn>(input.clone())?;
|
let item_fn = syn::parse2::<ItemFn>(input.clone())?;
|
||||||
|
|
||||||
check_extractor_count(&item_fn)?;
|
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_output_impls_into_response = check_output_impls_into_response(&item_fn);
|
||||||
let check_future_send = check_future_send(&item_fn);
|
let check_future_send = check_future_send(&item_fn);
|
||||||
|
|
||||||
@ -170,11 +189,29 @@ mod debug_handler {
|
|||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Attrs;
|
struct Attrs {
|
||||||
|
body_ty: Type,
|
||||||
|
}
|
||||||
|
|
||||||
impl Parse for Attrs {
|
impl Parse for Attrs {
|
||||||
fn parse(_input: syn::parse::ParseStream) -> syn::Result<Self> {
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
Ok(Self)
|
let mut body_ty = None;
|
||||||
|
|
||||||
|
while !input.is_empty() {
|
||||||
|
let ident = input.parse::<syn::Ident>()?;
|
||||||
|
if ident == "body" {
|
||||||
|
input.parse::<Token![=]>()?;
|
||||||
|
body_ty = Some(input.parse()?);
|
||||||
|
} else {
|
||||||
|
return Err(syn::Error::new_spanned(ident, "unknown argument"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = input.parse::<Token![,]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
if !item_fn.sig.generics.params.is_empty() {
|
||||||
return syn::Error::new_spanned(
|
return syn::Error::new_spanned(
|
||||||
&item_fn.sig.generics,
|
&item_fn.sig.generics,
|
||||||
@ -237,7 +274,7 @@ mod debug_handler {
|
|||||||
#[allow(warnings)]
|
#[allow(warnings)]
|
||||||
fn #name()
|
fn #name()
|
||||||
where
|
where
|
||||||
#ty: ::axum::extract::FromRequest<::axum::body::Body> + Send,
|
#ty: ::axum::extract::FromRequest<#body_ty> + Send,
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
error: unexpected token
|
|
||||||
--> tests/fail/attrs.rs:3:17
|
|
||||||
|
|
|
||||||
3 | #[debug_handler(foo)]
|
|
||||||
| ^^^
|
|
5
axum-debug/tests/fail/invalid_attrs.stderr
Normal file
5
axum-debug/tests/fail/invalid_attrs.stderr
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
error: unknown argument
|
||||||
|
--> tests/fail/invalid_attrs.rs:3:17
|
||||||
|
|
|
||||||
|
3 | #[debug_handler(foo)]
|
||||||
|
| ^^^
|
10
axum-debug/tests/pass/different_request_body_type.rs
Normal file
10
axum-debug/tests/pass/different_request_body_type.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use axum::{body::BoxBody, http::Request};
|
||||||
|
use axum_debug::debug_handler;
|
||||||
|
|
||||||
|
#[debug_handler(body = BoxBody)]
|
||||||
|
async fn handler(_: Request<BoxBody>) {}
|
||||||
|
|
||||||
|
#[debug_handler(body = axum::body::BoxBody,)]
|
||||||
|
async fn handler_with_trailing_comma_and_type_path(_: Request<axum::body::BoxBody>) {}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -1,7 +1,4 @@
|
|||||||
use axum::{
|
use axum::response::{IntoResponse, Response};
|
||||||
body::BoxBody,
|
|
||||||
response::{IntoResponse, Response},
|
|
||||||
};
|
|
||||||
use axum_debug::debug_handler;
|
use axum_debug::debug_handler;
|
||||||
|
|
||||||
struct A;
|
struct A;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user