rustrust-axum

How to return custom Json type from axum handler?


This code works:

#[derive(Debug, Clone)]
struct SharedState {
  auth: String,
  token: String,
}
fn router() -> Router {
  let shared_state = Arc::new(Mutex::new(SharedState {
    auth: "1234".to_owned(),
    token: "abcd".to_owned(),
  }));
  Router::new() .route("/shared_state", 
    get(get_shared_state)).with_state(shared_state)
}
pub async fn get_shared_state(
  State(shared_state): State<Arc<Mutex<SharedState>>>,
) -> (StatusCode, Json<Value>) {
  let state = shared_state.lock().unwrap();
  println!("shared_state: {:?}", state);
  (
    StatusCode::OK,
    Json(json!({
      "auth": state.auth.clone(),
      "token": state.token.clone()
    })),
  )
}

But if I change the Json<Value> to Json<SharedState> like below

pub async fn get_shared_state(
  State(shared_state): State<Arc<Mutex<SharedState>>>,
) -> (StatusCode, Json<SharedState>) {
  let state = shared_state.lock().unwrap();
  println!("shared_state: {:?}", state);
  (StatusCode::OK, Json(state.clone()))
}

I got the following error:

the trait bound `fn(State<Arc<Mutex<...>>>) -> ... 
{get_shared_state}: Handler<_, _>` is not satisfied
Consider using `#[axum::debug_handler]` to improve the error message
the following other types implement trait `Handler<T, S>`:
  `MethodRouter<S>` implements `Handler<(), S>`
  `axum::handler::Layered<L, H, T, S>` implements `Handler<T, S>`

main.rs(67, 10): required by a bound introduced by this call
method_routing.rs(326, 16): required by a bound in `MethodRouter::<S>::get`

Solution

  • To return a Json response, the wrapped type need to implement Serialize from serde.

    In yours and many cases, just adding the derive macro to your type is the way to go:

    [dependencies]
    serde = { version = "1.0.219", features = ["derive"] }
    
    use serde::Serialize;
    
    #[derive(Debug, Clone, Serialize)]
    struct SharedState {
        auth: String,
        token: String,
    }
    

    After that, your handler will compile and work as you'd expect. If you need something slightly different, the derive macro is fairly customizable or of course you can implement it manually.