Url serialization of a single field with serde

I probably overlooked something obvious, but I can't find a way to serialize a single form value with serde. Essentially I'm looking for a de-facto standard lib for something like this:

#[derive(serde::Serialize)]
enum Foo {
    Bar,
}

fn encode(val: impl serde::Serialize) -> String {
    serde_urlencoded::to_string(&[('x', val)])
        .unwrap()
        .split_once("=")
        .unwrap()
        .1
        .to_owned()
}

fn main() {
    println!("{}", encode(Foo::Bar));  // Bar
}

A URL-encoded value is by definition a collection of key-value pairs. Serializing an atomic value directly results in the serializer returning an error: "top-level serializer supports only maps and structs". I don't think what you want is possible.

What do you need this for? I'm pretty sure there is a better solution for what you are actually trying to achieve.

1 Like

I need it to put the value into an html form

What exactly do you mean by "put it in an HTML form"? Do you need to display it in the browser? Do you need to send it to a server? Can you elaborate?

Yep, just to put it into a html string to display in the browser.

What kind of types are you anticipating? If it's always a simple enum with unit variants, then you have a lot of options, the two simplest I can think of are:

  • serialize to a serde_json::Value and extract the resulting Value::String, or
  • use strum to #[derive(AsRefStr)] and get a &'static string directly out of the enum.

What kind of types are you anticipating?

Any serializable as you can see from the example.

serialize to a serde_json::Value and extract the resulting Value::String

It won't escape things properly:

fn encode(val: impl serde::Serialize) -> String {
    serde_urlencoded::to_string(&[('x', val)])
        .unwrap()
        .split_once("=")
        .unwrap()
        .1
        .to_owned()
}

fn encode_serdejson(val: impl serde::Serialize) -> String {
    serde_json::to_value(val)
        .unwrap()
        .as_str()
        .unwrap()
        .to_owned()
}

fn main() {
    let raw = "&<";
    println!("{}", encode(raw)); // "%26%3C"
    println!("{}", encode_serdejson(raw)); // "&<"
}

use strum to #[derive(AsRefStr)] and get a &'static string directly out of the enum.

I'd prefer using Serde as it's already derived anyway

That's likely not the case – what if you have a complex type, e.g. a HashMap, a struct, or even just some sort of sequence? What do you want to do in that case?

If you want to URL-escape a string, then use form_urlencoded for that purpose. However, for displaying in HTML, you probably want HTML escaping instead.

1 Like

That's likely not the case – what if you have a complex type, e.g. a HashMap , a struct, or even just some sort of sequence? What do you want to do in that case?

In my case I'm using htmx to pass the form as axum::extract::Json<MyInput> to a handler, so serde is already there and all fields of MyInput implement Serialize. So I'm ok for the encoder to accept any serializable even if output won't make sense for complex types.

you probably want HTML escaping instead

That makes sense, thank you :slight_smile:

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.