Axum POST handler with both app state and parameters?

Trying to implement POST handler in Axum, I can't find anything beyond most basic examples.

  1. official docs just shows the signature.
  2. a discussion in the forum shows a real example with some real parameters, but not app state. :frowning:
  3. examples in axum repo show a form and a basic handler that accepts only the form struct, not app state.

How do I put both the state and form data in the handler signature?

Here's what I made by active guessing:

...route("/data/v1/move/", post(do_move))

#[derive(Deserialize, Debug)]
pub struct MoveRequest { point_id: PointId, dist: f32 }

async fn do_move(Form(_mr): Form<MoveRequest>, State(ast): State<MyAppState>) -> Result<(HeaderMap, Bytes), (StatusCode, String)> {
    Ok((HeaderMap::new(), Bytes::from("updated ok")))
}

Produces compilation error:

the trait bound `fn(Form<MoveRequest>, axum::extract::State<MyAppState>) -> impl Future<Output = Result<(HeaderMap, axum::body::Bytes), (StatusCode, std::string::String)>> {move_platform}: Handler<_, _>` is not satisfied
the following other types implement trait `Handler<T, S>`:
  <Layered<L, H, T, S> as Handler<T, S>>
  <MethodRouter<S> as Handler<(), S>>

No idea what's wrong here. Function do_move did work before I added the first parameter (Form<MoveRequest>).

Nevermind. Somewhere in VSCode tooltips, I saw a piece of doc on Form that said that it must be the last extractor in signature, and turns out swapping arguments fixed it:

async fn do_move(State(ast): State<MyAppState>, Form(_mr): Form<MoveRequest>) -> Result<(HeaderMap, Bytes), (StatusCode, String)> {
    Ok((HeaderMap::new(), Bytes::from("updated ok")))
}

As extractor

If used as an extractor, Form will deserialize form data from the request, specifically:

  • If the request has a method of GET or HEAD, the form data will be read from the query string (same as with [Query])
  • If the request has a different method, the form will be read from the body of the request. It must have a content-type of application/x-www-form-urlencoded for this to work. If you want to parse multipart/form-data request bodies, use [Multipart] instead.
    ...
    :warning: Since parsing form data might require consuming the request body, the Form extractor must be last if there are multiple extractors in a handler. See "the order of extractors".

I've just learned that these structures in signature generate own pieces of code that run, and they have some order that's important.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.