Loading page…
Rust walkthroughs
Loading page…
http::Request<hyper::Body> and http::Request<axum::body::Body> in handler functions?http::Request<hyper::Body> and http::Request<axum::body::Body> represent the same underlying concept—an HTTP request with a body—but come from different versions of the ecosystem. In hyper 0.14 and earlier, hyper::Body was a concrete type implementing http_body::Body directly. In hyper 1.0 and axum 0.7+, axum::body::Body is a type alias for http_body::Body<Bytes> or the crate's re-export that abstracts over different body implementations. The key difference is that axum::body::Body supports both hyper 1.0's new body model and provides additional extraction and middleware integration, while hyper::Body (from older versions) was tightly coupled to hyper's older async runtime model. When writing axum handlers, use axum::body::Body for compatibility with axum's extractor ecosystem, while hyper::Body appears in legacy code or when interfacing directly with hyper 0.14.
// hyper 0.14 (legacy)
use hyper::Body; // Concrete type specific to hyper
// axum 0.6 and earlier (built on hyper 0.14)
use axum::body::Body; // Re-export of hyper::Body
// hyper 1.0+ and axum 0.7+
use axum::body::Body; // Abstracts over http_body::Body implementations
use http_body::Body; // Trait for body implementations
// The http crate is agnostic
use http::Request; // Generic over any body typeThe http::Request<B> type is generic over any body type B.
// Legacy hyper 0.14 style
use hyper::{Body, Request, Response};
use hyper::service::{make_service_fn, service_fn};
async fn handle(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
// Body is a concrete type specific to hyper 0.14
let body_bytes = hyper::body::to_bytes(req.into_body()).await?;
Ok(Response::new(Body::from("Hello")))
}
#[tokio::main]
async fn main() {
// hyper 0.14 server setup
let make_svc = make_service_fn(|_conn| {
async { Ok::<_, hyper::Error>(service_fn(handle)) }
});
// Server uses hyper::Body directly
}hyper::Body in hyper 0.14 was a concrete type with stream-based body handling.
// Modern axum 0.7+ style (hyper 1.0)
use axum::{
body::Body,
extract::Request,
response::Response,
routing::get,
Router,
};
async fn handle(req: Request) -> Response<Body> {
// Body abstracts over different body implementations
Response::new(Body::from("Hello"))
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handle));
// Axum handles body type conversion internally
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}axum::body::Body in axum 0.7+ works with hyper 1.0's body model.
// In axum 0.6 (hyper 0.14):
// axum::body::Body is an alias for hyper::Body
// http::Request<hyper::Body> is the request type
// In axum 0.7+ (hyper 1.0):
// axum::body::Body wraps different underlying types
// http::Request<axum::body::Body> is the request type
use http::Request;
// The Request type is the same, body type differs
fn process_request_v06(req: Request<hyper::Body>) {
// hyper 0.14 body
}
fn process_request_v07(req: Request<axum::body::Body>) {
// axum 0.7+ body (hyper 1.0 compatible)
}The http::Request type is shared; the body type parameter differs.
use axum::{
body::Body,
extract::Request,
};
use http_body_util::BodyExt;
async fn get_body_bytes(req: Request) -> Vec<u8> {
// Collect body into bytes
let body = req.into_body();
let bytes = body.collect().await.unwrap().to_bytes();
bytes.to_vec()
}
// Alternative using axum's Bytes extractor
use axum::body::Bytes;
async fn extract_bytes(body: Bytes) -> Vec<u8> {
body.to_vec()
}Both versions support collecting body to bytes.
use axum::body::Body;
use axum::extract::Request;
use http_body_util::BodyExt;
use futures::StreamExt;
async fn stream_body(req: Request) {
let mut body = req.into_body();
// Using http_body_util for streaming
while let Some(frame) = body.frame().await.transpose().unwrap() {
if let Some(data) = frame.data_ref() {
println!("Received {} bytes", data.len());
}
}
}
// In hyper 0.14:
async fn stream_legacy(req: hyper::Request<hyper::Body>) {
let mut body = req.into_body();
while let Some(chunk) = body.next().await {
let chunk = chunk.unwrap();
println!("Received {} bytes", chunk.len());
}
}Body streaming differs between hyper 0.14 and hyper 1.0+.
use axum::{
body::Body,
extract::Request,
response::{Response, IntoResponse},
};
// Modern axum 0.7+ handler
async fn handler_v07(req: Request) -> Response<Body> {
// Request is http::Request<axum::body::Body>
Response::new(Body::from("Response"))
}
// Legacy axum 0.6 handler
async fn handler_v06(req: hyper::Request<hyper::Body>) -> hyper::Response<hyper::Body> {
// Request is http::Request<hyper::Body>
hyper::Response::new(hyper::Body::from("Response"))
}
// Using IntoResponse (works in both)
async fn handler_into_response() -> impl IntoResponse {
// IntoResponse handles body conversion
"Response"
}Modern axum uses axum::body::Body; legacy uses hyper::Body.
use axum::body::Body;
use http_body_util::BodyExt;
// Convert between body types
async fn convert_body(body: Body) -> Vec<u8> {
// Body -> Bytes
let bytes = body.collect().await.unwrap().to_bytes();
bytes.to_vec()
}
// Create body from various sources
fn create_bodies() {
// From bytes
let body1 = Body::from("Hello");
// From vec
let body2 = Body::from(vec![1, 2, 3]);
// From string
let body3 = Body::from(String::from("World"));
// Empty body
let body4 = Body::empty();
}Body::from accepts various types that implement Into<Body>.
use axum::{
body::{Body, Bytes},
extract::Request,
response::Response,
};
// Method 1: Extract whole body
async fn extract_body_bytes(body: Bytes) -> Vec<u8> {
body.to_vec()
}
// Method 2: Extract request and get body
async fn extract_request_body(req: Request) -> Response {
let body = req.into_body();
// Process body...
Response::new(Body::from("OK"))
}
// Method 3: Use Body extractor directly
async fn extract_body(body: Body) -> Response {
// Body implements IntoResponse
Response::new(body)
}Axum provides multiple ways to access request body content.
use axum::{
body::Body,
response::{Response, IntoResponse},
};
use http_body_util::Full;
use bytes::Bytes;
async fn create_responses() {
// Simple string body
let response1 = Response::new(Body::from("Hello"));
// Bytes body
let response2 = Response::new(Body::from(Bytes::from("Hello")));
// Using IntoResponse
let response3 = "Hello".into_response();
// JSON response (with axum::Json)
let response4 = axum::Json(serde_json::json!({"message": "hello"})).into_response();
}Multiple types can be converted to response bodies.
use axum::body::Body;
use http_body_util::BodyExt;
// In hyper 1.0, bodies implement http_body::Body trait
// axum::body::Body wraps this trait
async fn use_with_hyper1(body: Body) {
// Body implements http_body::Body
let bytes = body.collect().await.unwrap().to_bytes();
// Can convert to different body types
let body2 = Body::from(bytes);
}axum::body::Body works with hyper 1.0's http_body::Body trait.
// In hyper 0.14, hyper::Body was the concrete type
// It implemented Stream<Item = Result<Bytes, Error>>
async fn use_with_hyper014(body: hyper::Body) {
use hyper::body::to_bytes;
// Collect to bytes
let bytes = to_bytes(body).await.unwrap();
}
// The difference:
// hyper 0.14: hyper::Body implements Stream
// hyper 1.0+: Body implements http_body::Body traitHyper 0.14 used Stream; hyper 1.0+ uses the http_body::Body trait.
// axum 0.6 and earlier
// pub type Body = hyper::Body;
// axum 0.7+
// pub type Body = <...>; // Abstract body type
use axum::body::Body;
// Always use axum::body::Body in axum handlers
// The type alias ensures compatibility with axum version
// In generic code, use http_body::Body trait
use http_body::Body as HttpBody;
async fn generic_handler<B>(req: http::Request<B>)
where
B: HttpBody,
{
// Work with any body type
}Use axum::body::Body for handlers; use http_body::Body trait for generic code.
use axum::{
body::Body,
extract::Request,
middleware::Next,
response::Response,
};
async fn body_middleware(req: Request, next: Next) -> Response {
// Read body
let (parts, body) = req.into_parts();
let bytes = body.collect().await.unwrap().to_bytes();
println!("Body size: {}", bytes.len());
// Reconstruct request
let req = Request::from_parts(parts, Body::from(bytes));
next.run(req).await
}Middleware can read and reconstruct bodies using Body::from.
use axum::{
body::Body,
extract::Request,
response::Response,
};
use http_body_util::BodyExt;
async fn handle_body_errors(req: Request) -> Result<Response, Box<dyn std::error::Error>> {
let body = req.into_body();
// Body operations can fail
match body.collect().await {
Ok(collected) => {
let bytes = collected.to_bytes();
Ok(Response::new(Body::from(bytes)))
}
Err(e) => {
// Handle body collection error
Err(e.into())
}
}
}Body operations return Result with error handling.
use axum::body::Body;
use http_body::Body as HttpBody;
// Body implements HttpBody
fn require_body_trait(body: Body) -> impl HttpBody {
body
}
// Common trait bounds
use http_body_util::BodyExt;
async fn with_bounds<B>(body: B) -> Vec<u8>
where
B: HttpBody + Send + 'static,
B::Error: std::error::Error + Send + Sync,
{
body.collect().await.unwrap().to_bytes().to_vec()
}axum::body::Body implements http_body::Body with necessary bounds.
use axum::body::Body;
use axum::extract::Request;
use http_body_util::BodyExt;
async fn efficient_body_handling(req: Request) {
// If you need the whole body, collect once
let bytes = req.into_body().collect().await.unwrap().to_bytes();
// Reuse the bytes
let body = Body::from(bytes.clone());
// Avoid: Multiple collections of the same body
// Bodies can only be consumed once
}
// For streaming, avoid buffering entire body
async fn stream_efficiently(req: Request) {
use futures::StreamExt;
// Process chunks as they arrive
let mut body = req.into_body();
while let Some(frame) = body.frame().await.transpose().unwrap() {
if let Some(data) = frame.data_ref() {
// Process data immediately
}
}
}Bodies can only be consumed once; avoid unnecessary buffering.
// Before (hyper 0.14 / axum 0.6):
use hyper::{Body, Request, Response};
async fn old_handler(req: Request<Body>) -> Response<Body> {
let bytes = hyper::body::to_bytes(req.into_body()).await.unwrap();
Response::new(Body::from(bytes))
}
// After (hyper 1.0 / axum 0.7+):
use axum::body::Body;
use axum::extract::Request;
use axum::response::Response;
use http_body_util::BodyExt;
async fn new_handler(req: Request) -> Response {
let bytes = req.into_body().collect().await.unwrap().to_bytes();
Response::new(Body::from(bytes))
}Key migration changes: hyper::body::to_bytes becomes body.collect().await.to_bytes().
// Hyper 0.14 / Axum 0.6:
// - hyper::Body is the concrete type
// - hyper::body::to_bytes() for collecting
// - hyper::Request<hyper::Body> for requests
// - hyper::Response<hyper::Body> for responses
// Hyper 1.0 / Axum 0.7+:
// - axum::body::Body is the abstract type
// - body.collect().await for collecting
// - axum::extract::Request for requests (wraps http::Request)
// - axum::response::Response for responses (wraps http::Response)
// - http_body::Body trait for generic handlingMigration requires updating body handling APIs.
hyper::Body (hyper 0.14):
Stream<Item = Result<Bytes, Error>>hyper::body::to_bytes()axum::body::Body (axum 0.7+):
http_body::Body traitbody.collect().awaithttp_body_util combinatorsKey differences:
hyper::Body is concrete; axum::body::Body abstracts over implementationsStream; new uses http_body::Bodyhyper::body::to_bytes; new uses body.collect()When to use each:
axum::body::Body in axum 0.7+ handlershyper::Body only for legacy hyper 0.14 codehttp_body::Body trait for generic body handlingBytes, String, Json) over raw body accessMigration path:
hyper::Body with axum::body::Bodyhyper::body::to_bytes() with body.collect().await?.to_bytes()hyper::Request with axum::extract::Requesthyper::Response with axum::response::Response