How to handle form inputs with multiple values?

Hello,

I'm trying to use serde with axum to extract a form input with multiple values. I've tried a number of varying structs, but I can't seem to get it working correctly. Setting up a struct with Vec<String> seems to make the most sense to me, but the following snippet returns "Failed to deserialize form body: invalid type: string "A", expected a sequence" when posting with curl http://localhost:3000 -d 'letters[]=A&letters[]=B'

use axum::{
    extract::Form,
    http::StatusCode
};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub struct GuessForm {
    #[serde(rename = "letters[]")]
    pub letters: Vec<String>,
}

pub async fn guess(
    Form(guess): Form<GuessForm>
) -> (StatusCode, &'static str) {
    (StatusCode::OK, "ok")
}

When I change letters to a String, and repeat the curl request, I get "Failed to deserialize form body: duplicate field letters[]".

This seems like something I should be able to do without building a custom deserializer, so I wanted to check before going down that path.

Thanks in advance for any assistance!

axum uses serde_urlencoded under the hood for deserializing form data. Unfortunately, serde_urlencoded doesn't support arrays. You could build a custom Deserialize implementation for letters, but honestly, if I were you I'd just pass the data as Json inside the request body instead and avoid all the pitfalls of x-www-form-urlencoded entirely.

1 Like

Thanks for the response! I want this to work with an HTML form without JavaScript enabled, so it looks like I will have to build a custom deserializer.

I see. You might find the code snippet from this answer a helpful starting point for writing your own deserialization logic:

Of course you just want to read a Vec<String> and not a HashMap<String, HashMap<String, String>>, but I think the basic structure can be adopted to fit your use-case.


Edit: I started building a rudimentary example for your case: playground.

2 Likes

For others finding this thread via search results, this github issue is quite helpful. TLDR: use the Form extractor from the axum-extras crate, rather than the axum crate itself.

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.