mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-25 00:00:23 +02:00
Remove B type param (#1751)
Co-authored-by: Jonas Platte <[email protected]> Co-authored-by: Michael Scofield <[email protected]>
This commit is contained in:
co-authored by
Jonas Platte
Michael Scofield
parent
9be0ea934c
commit
4e4c29175f
@@ -6,7 +6,7 @@
|
||||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::{self, BoxBody, Bytes, Full},
|
||||
body::{Body, Bytes},
|
||||
extract::FromRequest,
|
||||
http::{Request, StatusCode},
|
||||
middleware::{self, Next},
|
||||
@@ -16,7 +16,6 @@ use axum::{
|
||||
};
|
||||
use std::net::SocketAddr;
|
||||
use tower::ServiceBuilder;
|
||||
use tower_http::ServiceBuilderExt;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
@@ -29,11 +28,9 @@ async fn main() {
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
let app = Router::new().route("/", post(handler)).layer(
|
||||
ServiceBuilder::new()
|
||||
.map_request_body(body::boxed)
|
||||
.layer(middleware::from_fn(print_request_body)),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route("/", post(handler))
|
||||
.layer(ServiceBuilder::new().layer(middleware::from_fn(print_request_body)));
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
tracing::debug!("listening on {}", addr);
|
||||
@@ -45,8 +42,8 @@ async fn main() {
|
||||
|
||||
// middleware that shows how to consume the request body upfront
|
||||
async fn print_request_body(
|
||||
request: Request<BoxBody>,
|
||||
next: Next<BoxBody>,
|
||||
request: Request<Body>,
|
||||
next: Next<Body>,
|
||||
) -> Result<impl IntoResponse, Response> {
|
||||
let request = buffer_request_body(request).await?;
|
||||
|
||||
@@ -55,7 +52,7 @@ async fn print_request_body(
|
||||
|
||||
// the trick is to take the request apart, buffer the body, do what you need to do, then put
|
||||
// the request back together
|
||||
async fn buffer_request_body(request: Request<BoxBody>) -> Result<Request<BoxBody>, Response> {
|
||||
async fn buffer_request_body(request: Request<Body>) -> Result<Request<Body>, Response> {
|
||||
let (parts, body) = request.into_parts();
|
||||
|
||||
// this wont work if the body is an long running stream
|
||||
@@ -65,7 +62,7 @@ async fn buffer_request_body(request: Request<BoxBody>) -> Result<Request<BoxBod
|
||||
|
||||
do_thing_with_request_body(bytes.clone());
|
||||
|
||||
Ok(Request::from_parts(parts, body::boxed(Full::from(bytes))))
|
||||
Ok(Request::from_parts(parts, Body::from(bytes)))
|
||||
}
|
||||
|
||||
fn do_thing_with_request_body(bytes: Bytes) {
|
||||
@@ -81,13 +78,13 @@ struct BufferRequestBody(Bytes);
|
||||
|
||||
// we must implement `FromRequest` (and not `FromRequestParts`) to consume the body
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S, BoxBody> for BufferRequestBody
|
||||
impl<S> FromRequest<S> for BufferRequestBody
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let body = Bytes::from_request(req, state)
|
||||
.await
|
||||
.map_err(|err| err.into_response())?;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//! - Complexity: Manually implementing `FromRequest` results on more complex code
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::Body,
|
||||
extract::{rejection::JsonRejection, FromRequest, MatchedPath},
|
||||
http::Request,
|
||||
http::StatusCode,
|
||||
@@ -22,15 +23,14 @@ pub async fn handler(Json(value): Json<Value>) -> impl IntoResponse {
|
||||
pub struct Json<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B> for Json<T>
|
||||
impl<S, T> FromRequest<S> for Json<T>
|
||||
where
|
||||
axum::Json<T>: FromRequest<S, B, Rejection = JsonRejection>,
|
||||
axum::Json<T>: FromRequest<S, Rejection = JsonRejection>,
|
||||
S: Send + Sync,
|
||||
B: Send + 'static,
|
||||
{
|
||||
type Rejection = (StatusCode, axum::Json<Value>);
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let (mut parts, body) = req.into_parts();
|
||||
|
||||
// We can use other extractors to provide better rejection messages.
|
||||
|
||||
@@ -37,8 +37,9 @@ async fn main() {
|
||||
|
||||
let router_svc = Router::new().route("/", get(|| async { "Hello, World!" }));
|
||||
|
||||
let service = tower::service_fn(move |req: Request<Body>| {
|
||||
let service = tower::service_fn(move |req: Request<_>| {
|
||||
let router_svc = router_svc.clone();
|
||||
let req = req.map(Body::new);
|
||||
async move {
|
||||
if req.method() == Method::CONNECT {
|
||||
proxy(req).await
|
||||
|
||||
@@ -8,13 +8,11 @@ use axum::{routing::get, Router};
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::TcpListener;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tower_hyper_http_body_compat::{
|
||||
HttpBody1ToHttpBody04, TowerService03HttpServiceAsHyper1HttpService,
|
||||
};
|
||||
use tower_hyper_http_body_compat::TowerService03HttpServiceAsHyper1HttpService;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
// this is hyper 1.0
|
||||
use hyper::{body::Incoming, server::conn::http1};
|
||||
use hyper::server::conn::http1;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -26,8 +24,7 @@ async fn main() {
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
// you have to use `HttpBody1ToHttpBody04<Incoming>` as the second type parameter to `Router`
|
||||
let app: Router<_, HttpBody1ToHttpBody04<Incoming>> = Router::new()
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async { "Hello, World!" }))
|
||||
// we can still add regular tower middleware
|
||||
.layer(TraceLayer::new_for_http());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod};
|
||||
use tokio_openssl::SslStream;
|
||||
|
||||
use axum::{extract::ConnectInfo, routing::get, Router};
|
||||
use axum::{body::Body, extract::ConnectInfo, http::Request, routing::get, Router};
|
||||
use futures_util::future::poll_fn;
|
||||
use hyper::server::{
|
||||
accept::Accept,
|
||||
@@ -68,7 +68,7 @@ async fn main() {
|
||||
|
||||
let protocol = protocol.clone();
|
||||
|
||||
let svc = app.make_service(&stream);
|
||||
let svc = MakeService::<_, Request<Body>>::make_service(&mut app, &stream);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let ssl = Ssl::new(acceptor.context()).unwrap();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! cargo run -p example-low-level-rustls
|
||||
//! ```
|
||||
|
||||
use axum::{extract::ConnectInfo, routing::get, Router};
|
||||
use axum::{body::Body, extract::ConnectInfo, http::Request, routing::get, Router};
|
||||
use futures_util::future::poll_fn;
|
||||
use hyper::server::{
|
||||
accept::Accept,
|
||||
@@ -24,7 +24,7 @@ use tokio_rustls::{
|
||||
rustls::{Certificate, PrivateKey, ServerConfig},
|
||||
TlsAcceptor,
|
||||
};
|
||||
use tower::MakeService;
|
||||
use tower::make::MakeService;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
@@ -53,7 +53,7 @@ async fn main() {
|
||||
|
||||
let protocol = Arc::new(Http::new());
|
||||
|
||||
let mut app = Router::new()
|
||||
let mut app = Router::<()>::new()
|
||||
.route("/", get(handler))
|
||||
.into_make_service_with_connect_info::<SocketAddr>();
|
||||
|
||||
@@ -67,7 +67,7 @@ async fn main() {
|
||||
|
||||
let protocol = protocol.clone();
|
||||
|
||||
let svc = app.make_service(&stream);
|
||||
let svc = MakeService::<_, Request<Body>>::make_service(&mut app, &stream);
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Ok(stream) = acceptor.accept(stream).await {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::Body,
|
||||
extract::FromRequest,
|
||||
http::{header::CONTENT_TYPE, Request, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
@@ -51,17 +52,16 @@ async fn handler(JsonOrForm(payload): JsonOrForm<Payload>) {
|
||||
struct JsonOrForm<T>(T);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B> for JsonOrForm<T>
|
||||
impl<S, T> FromRequest<S> for JsonOrForm<T>
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
Json<T>: FromRequest<(), B>,
|
||||
Form<T>: FromRequest<(), B>,
|
||||
Json<T>: FromRequest<()>,
|
||||
Form<T>: FromRequest<()>,
|
||||
T: 'static,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let content_type_header = req.headers().get(CONTENT_TYPE);
|
||||
let content_type = content_type_header.and_then(|value| value.to_str().ok());
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
//! ```
|
||||
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::State,
|
||||
http::{uri::Uri, Request, Response},
|
||||
http::{uri::Uri, Request},
|
||||
response::{IntoResponse, Response},
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use hyper::{client::HttpConnector, Body};
|
||||
use hyper::client::HttpConnector;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
type Client = hyper::client::Client<HttpConnector, Body>;
|
||||
@@ -22,7 +24,7 @@ type Client = hyper::client::Client<HttpConnector, Body>;
|
||||
async fn main() {
|
||||
tokio::spawn(server());
|
||||
|
||||
let client = Client::new();
|
||||
let client: Client = hyper::Client::builder().build(HttpConnector::new());
|
||||
|
||||
let app = Router::new().route("/", get(handler)).with_state(client);
|
||||
|
||||
@@ -34,7 +36,7 @@ async fn main() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn handler(State(client): State<Client>, mut req: Request<Body>) -> Response<Body> {
|
||||
async fn handler(State(client): State<Client>, mut req: Request<Body>) -> Response {
|
||||
let path = req.uri().path();
|
||||
let path_query = req
|
||||
.uri()
|
||||
@@ -46,7 +48,7 @@ async fn handler(State(client): State<Client>, mut req: Request<Body>) -> Respon
|
||||
|
||||
*req.uri_mut() = Uri::try_from(uri).unwrap();
|
||||
|
||||
client.request(req).await.unwrap()
|
||||
client.request(req).await.unwrap().into_response()
|
||||
}
|
||||
|
||||
async fn server() {
|
||||
|
||||
@@ -71,7 +71,10 @@ fn using_serve_dir_with_handler_as_service() -> Router {
|
||||
(StatusCode::NOT_FOUND, "Not found")
|
||||
}
|
||||
|
||||
let serve_dir = ServeDir::new("assets").not_found_service(handle_404.into_service());
|
||||
// you can convert handler function to service
|
||||
let service = handle_404.into_service();
|
||||
|
||||
let serve_dir = ServeDir::new("assets").not_found_service(service);
|
||||
|
||||
Router::new()
|
||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
//! ```
|
||||
|
||||
use axum::{
|
||||
body::Bytes,
|
||||
extract::{BodyStream, Multipart, Path},
|
||||
http::StatusCode,
|
||||
body::{Body, Bytes},
|
||||
extract::{Multipart, Path},
|
||||
http::{Request, StatusCode},
|
||||
response::{Html, Redirect},
|
||||
routing::{get, post},
|
||||
BoxError, Router,
|
||||
@@ -52,9 +52,9 @@ async fn main() {
|
||||
// POST'ing to `/file/foo.txt` will create a file called `foo.txt`.
|
||||
async fn save_request_body(
|
||||
Path(file_name): Path<String>,
|
||||
body: BodyStream,
|
||||
request: Request<Body>,
|
||||
) -> Result<(), (StatusCode, String)> {
|
||||
stream_to_file(&file_name, body).await
|
||||
stream_to_file(&file_name, request.into_body()).await
|
||||
}
|
||||
|
||||
// Handler that returns HTML for a multipart form.
|
||||
|
||||
@@ -148,7 +148,7 @@ mod tests {
|
||||
.request(
|
||||
Request::builder()
|
||||
.uri(format!("http://{}", addr))
|
||||
.body(Body::empty())
|
||||
.body(hyper::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
@@ -165,11 +165,21 @@ mod tests {
|
||||
let mut app = app();
|
||||
|
||||
let request = Request::builder().uri("/").body(Body::empty()).unwrap();
|
||||
let response = app.ready().await.unwrap().call(request).await.unwrap();
|
||||
let response = ServiceExt::<Request<Body>>::ready(&mut app)
|
||||
.await
|
||||
.unwrap()
|
||||
.call(request)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
let request = Request::builder().uri("/").body(Body::empty()).unwrap();
|
||||
let response = app.ready().await.unwrap().call(request).await.unwrap();
|
||||
let response = ServiceExt::<Request<Body>>::ready(&mut app)
|
||||
.await
|
||||
.unwrap()
|
||||
.call(request)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
@@ -186,7 +196,14 @@ mod tests {
|
||||
.uri("/requires-connect-into")
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
let response = app.ready().await.unwrap().call(request).await.unwrap();
|
||||
let response = app
|
||||
.as_service()
|
||||
.ready()
|
||||
.await
|
||||
.unwrap()
|
||||
.call(request)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::{rejection::FormRejection, Form, FromRequest},
|
||||
http::{Request, StatusCode},
|
||||
response::{Html, IntoResponse, Response},
|
||||
@@ -61,16 +62,15 @@ async fn handler(ValidatedForm(input): ValidatedForm<NameInput>) -> Html<String>
|
||||
pub struct ValidatedForm<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for ValidatedForm<T>
|
||||
impl<T, S> FromRequest<S> for ValidatedForm<T>
|
||||
where
|
||||
T: DeserializeOwned + Validate,
|
||||
S: Send + Sync,
|
||||
Form<T>: FromRequest<S, B, Rejection = FormRejection>,
|
||||
B: Send + 'static,
|
||||
Form<T>: FromRequest<S, Rejection = FormRejection>,
|
||||
{
|
||||
type Rejection = ServerError;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let Form(value) = Form::<T>::from_request(req, state).await?;
|
||||
value.validate()?;
|
||||
Ok(ValidatedForm(value))
|
||||
|
||||
Reference in New Issue
Block a user