# Handlers
A request handler is an asynchronous function that receives zero or more arguments (Extractors) and returns a type that implements the Responder trait.
##Handler Signature
A valid handler must be async and can take a maximum of 12 extractor arguments. (If you need more, you can bundle them into tuples).
async fn my_handler(
path: web::Path<u32>,
query: web::Query<MyQuery>,
json: web::Json<MyPayload>,
) -> impl Responder {
// ... logic ...
}##Non-blocking I/O
Because Actix Web handles thousands of requests concurrently on a small number of threads, you must never block the thread inside a handler. Blocking operations include:
- Synchronous file I/O (std::fs)
- Synchronous network calls (e.g., using blocking reqwest instead of async)
- Heavy CPU-bound computations without yielding
If you block a thread, no other requests assigned to that worker can be processed, leading to a massive drop in throughput and unresponsive servers.
If you must do a blocking operation (like using a legacy synchronous database driver), you should offload it to a thread pool using web::block:
use actix_web::{web, HttpResponse, Responder};
async fn blocking_handler() -> impl Responder {
// web::block executes the closure on a separate thread pool
// designed specifically for blocking tasks.
let result = web::block(|| {
// Do heavy CPU work or sync I/O here
std::thread::sleep(std::time::Duration::from_secs(2));
"Done!"
})
.await;
match result {
Ok(msg) => HttpResponse::Ok().body(msg),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}##Returning Custom Types
While you can always return HttpResponse, it is often cleaner to return your own domain types by implementing the Responder trait for them.
use actix_web::{body::BoxBody, http::header::ContentType, HttpRequest, HttpResponse, Responder};
use serde::Serialize;
#[derive(Serialize)]
struct MyObj {
name: String,
}
// Implement Responder for MyObj
impl Responder for MyObj {
type Body = BoxBody;
fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> {
let body = serde_json::to_string(&self).unwrap();
HttpResponse::Ok()
.content_type(ContentType::json())
.body(body)
}
}With this trait implemented, you can now return MyObj directly from your handler function!