axum

Attribute Macro debug_handler

Source
#[debug_handler]
Available on crate feature macros only.
Expand description

Generates better error messages when applied to handler functions.

While using axum, you can get long error messages for simple mistakes. For example:

use axum::{routing::get, Router};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(handler));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

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

You will get a long error message about function not implementing Handler trait. But why does this function not implement it? To figure it out, the debug_handler macro can be used.

#[debug_handler]
fn handler() -> &'static str {
    "Hello, world"
}
error: handlers must be async functions
  --> main.rs:xx:1
   |
xx | fn handler() -> &'static str {
   | ^^

As the error message says, handler function needs to be async.

use axum::{routing::get, Router, debug_handler};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(handler));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

#[debug_handler]
async fn handler() -> &'static str {
    "Hello, world"
}

§Changing state type

By default #[debug_handler] assumes your state type is () unless your handler has a axum::extract::State argument:

use axum::{debug_handler, extract::State};

#[debug_handler]
async fn handler(
    // this makes `#[debug_handler]` use `AppState`
    State(state): State<AppState>,
) {}

#[derive(Clone)]
struct AppState {}

If your handler takes multiple axum::extract::State arguments or you need to otherwise customize the state type you can set it with #[debug_handler(state = ...)]:

use axum::{debug_handler, extract::{State, FromRef}};

#[debug_handler(state = AppState)]
async fn handler(
    State(app_state): State<AppState>,
    State(inner_state): State<InnerState>,
) {}

#[derive(Clone)]
struct AppState {
    inner: InnerState,
}

#[derive(Clone)]
struct InnerState {}

impl FromRef<AppState> for InnerState {
    fn from_ref(state: &AppState) -> Self {
        state.inner.clone()
    }
}

§Limitations

This macro does not work for functions in an impl block that don’t have a self parameter:

use axum::{debug_handler, extract::Path};

struct App {}

impl App {
    #[debug_handler]
    async fn handler(Path(_): Path<String>) {}
}

This will yield an error similar to this:

error[E0425]: cannot find function `__axum_macros_check_handler_0_from_request_check` in this scope

§Performance

This macro has no effect when compiled with the release profile. (eg. cargo build --release)