> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tokio-rs/axum/llms.txt
> Use this file to discover all available pages before exploring further.

# Handlers

> Understand async handler functions in Axum

Handlers are async functions that process HTTP requests and produce responses. They form the core logic of your application.

## Basic handlers

A handler is any async function that implements the `Handler` trait:

```rust theme={null}
use axum::{Router, routing::get};

// Handler that returns an empty 200 OK response
async fn unit_handler() {}

// Handler that returns a plain text response
async fn string_handler() -> String {
    "Hello, World!".to_string()
}

let app = Router::new()
    .route("/", get(unit_handler))
    .route("/hello", get(string_handler));
```

## Handler signatures

Handlers can take extractors as arguments and return any type that implements `IntoResponse`:

<Steps>
  <Step title="Zero or more extractors">
    Extractors pull data from the request. They must implement `FromRequestParts` or `FromRequest`.

    ```rust theme={null}
    use axum::{extract::Path, http::HeaderMap};

    async fn handler(
        Path(id): Path<u32>,
        headers: HeaderMap,
    ) -> String {
        format!("ID: {}, Headers: {:?}", id, headers)
    }
    ```
  </Step>

  <Step title="Return type implements IntoResponse">
    The return type must be convertible to a response.

    ```rust theme={null}
    use axum::http::StatusCode;

    // Returns just a status code
    async fn handler() -> StatusCode {
        StatusCode::OK
    }

    // Returns a tuple (status, body)
    async fn handler_with_status() -> (StatusCode, &'static str) {
        (StatusCode::CREATED, "Resource created")
    }
    ```
  </Step>

  <Step title="Must be async">
    All handlers must be async functions.

    ```rust theme={null}
    // ✅ Correct
    async fn handler() -> &'static str {
        "response"
    }

    // ❌ Won't compile - not async
    fn handler() -> &'static str {
        "response"
    }
    ```
  </Step>
</Steps>

## Extractors in handlers

Handlers can extract data from requests using extractors:

```rust theme={null}
use axum::{
    extract::{Path, Query},
    body::Bytes,
    http::StatusCode,
};
use serde::Deserialize;

#[derive(Deserialize)]
struct Pagination {
    page: usize,
    per_page: usize,
}

async fn handler(
    Path(user_id): Path<u32>,
    Query(pagination): Query<Pagination>,
    body: Bytes,
) -> Result<String, StatusCode> {
    if let Ok(body_str) = String::from_utf8(body.to_vec()) {
        Ok(format!(
            "User {}, page {}, body: {}",
            user_id, pagination.page, body_str
        ))
    } else {
        Err(StatusCode::BAD_REQUEST)
    }
}
```

<Note>
  The order of extractors matters. See [Extractors](/concepts/extractors) for details.
</Note>

## Return types

Handlers can return various types:

<Tabs>
  <Tab title="Strings and static str">
    ```rust theme={null}
    async fn handler() -> &'static str {
        "Hello, World!"
    }

    async fn dynamic_handler() -> String {
        format!("Time: {}", std::time::SystemTime::now())
    }
    ```
  </Tab>

  <Tab title="Status codes">
    ```rust theme={null}
    use axum::http::StatusCode;

    async fn no_content() -> StatusCode {
        StatusCode::NO_CONTENT
    }

    async fn with_body() -> (StatusCode, &'static str) {
        (StatusCode::CREATED, "Resource created")
    }
    ```
  </Tab>

  <Tab title="JSON">
    ```rust theme={null}
    use axum::Json;
    use serde::Serialize;

    #[derive(Serialize)]
    struct User {
        id: u64,
        name: String,
    }

    async fn get_user() -> Json<User> {
        Json(User {
            id: 1,
            name: "Alice".to_string(),
        })
    }
    ```
  </Tab>

  <Tab title="Result types">
    ```rust theme={null}
    use axum::http::StatusCode;

    async fn may_fail() -> Result<String, StatusCode> {
        if some_condition() {
            Ok("Success".to_string())
        } else {
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }

    fn some_condition() -> bool { true }
    ```
  </Tab>
</Tabs>

## Error handling in handlers

Use `Result` types to handle errors:

```rust theme={null}
use axum::{
    extract::Json,
    http::StatusCode,
    response::IntoResponse,
};
use serde::Deserialize;

#[derive(Deserialize)]
struct CreateUser {
    name: String,
}

async fn create_user(
    Json(payload): Json<CreateUser>,
) -> Result<String, StatusCode> {
    if payload.name.is_empty() {
        return Err(StatusCode::BAD_REQUEST);
    }

    Ok(format!("Created user: {}", payload.name))
}
```

For more complex error handling, see [Error Handling](/concepts/error-handling).

## Converting handlers to services

Handlers can be converted to Tower services:

<CodeGroup>
  ```rust Without state theme={null}
  use axum::handler::HandlerWithoutStateExt;

  async fn handler() -> &'static str {
      "Hello"
  }

  let service = handler.into_service();
  ```

  ```rust With state theme={null}
  use axum::{
      extract::State,
      handler::Handler,
  };

  #[derive(Clone)]
  struct AppState {
      counter: u32,
  }

  async fn handler(State(state): State<AppState>) -> String {
      format!("Counter: {}", state.counter)
  }

  let state = AppState { counter: 0 };
  let service = handler.with_state(state);
  ```
</CodeGroup>

## Applying middleware to handlers

You can apply middleware directly to individual handlers:

```rust theme={null}
use axum::{
    Router,
    routing::get,
    handler::Handler,
};
use tower::limit::ConcurrencyLimitLayer;

async fn handler() -> &'static str {
    "Hello"
}

let layered_handler = handler.layer(ConcurrencyLimitLayer::new(64));

let app = Router::new()
    .route("/", get(layered_handler));
```

## Debugging handler errors

<Tip>
  Use the `#[axum::debug_handler]` macro to get better error messages during development:

  ```rust theme={null}
  use axum::debug_handler;

  #[debug_handler]
  async fn handler() -> String {
      "Hello".to_string()
  }
  ```

  This macro provides clearer compilation errors when your handler signature is incorrect.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Extractors" icon="download" href="/concepts/extractors">
    Learn how to extract data from requests
  </Card>

  <Card title="Responses" icon="arrow-up-from-bracket" href="/concepts/responses">
    Explore different response types
  </Card>
</CardGroup>
