Expand description
A serde
serializer for the “Form + JSON” encoding format.
This crate provides a robust serde
serializer for a specific hybrid data format
used by some web APIs, most notably Meta’s. This is not a standard
application/x-www-form-urlencoded
implementation; it follows a unique set of rules
where values are encoded as JSON.
The serializer is designed to be efficient and stream-based, performing the JSON serialization and percent-encoding in a single pass without creating intermediate string representations of the entire data structure.
§The “Form + JSON” Format
The format can be conceptually understood as a standard form-encoded payload where each value has been replaced by its JSON representation.
§Format Rules
-
Top-Level Structure: The root data structure must be a key-value pair collection, such as a Rust
struct
, amap
, or anenum
variant that holds data (newtype, struct, or tuple variants). Primitives (likeu32
) or simple sequences (likeVec<u32>
) are not valid at the top level. -
Key Serialization: Each key is converted to a string and then percent-encoded. The keys are never quoted.
-
Value Serialization: Each value is serialized to a JSON string, and that resulting JSON string is then percent-encoded.
- Simple types like numbers, booleans, and strings become their direct JSON
counterparts (e.g.,
123
,true
,"hello world"
). - Complex types like structs, maps, and vectors become JSON objects (
{...}
) or arrays ([...]
).
- Simple types like numbers, booleans, and strings become their direct JSON
counterparts (e.g.,
-
Separators: Key-value pairs are joined by
&
, and each key is separated from its value by=
.
§A Note on Compatibility
⚠️ Warning: This format is highly specific. Do not use this serializer to send data
to a standard web server expecting application/x-www-form-urlencoded
. A server
that isn’t explicitly designed to parse JSON-encoded values from a form payload
will not be able to understand the output of this crate.
§Examples
§Simple Struct
For simple values, the output looks very similar to standard form encoding.
use serde::Serialize;
use serde_metaform::to_string;
#[derive(Serialize)]
struct User {
id: u64,
username: String,
is_verified: bool,
}
let user = User {
id: 9001,
username: "gordon_freeman".to_string(),
is_verified: false,
};
let encoded = to_string(&user).unwrap();
// The values 9001, "gordon_freeman", and false are serialized as JSON primitives.
assert_eq!(encoded, "id=9001&username=gordon_freeman&is_verified=false");
§Complex Nested Data and Enums
The power of this format becomes clear with complex, nested data.
use serde::Serialize;
use serde_metaform::to_string;
#[derive(Serialize)]
struct Attachment {
type_: String,
url: String,
}
#[derive(Serialize)]
enum Message {
Text(String),
WithAttachment {
text: String,
attachment: Attachment,
},
}
let message = Message::WithAttachment {
text: "Check this out!".to_string(),
attachment: Attachment {
type_: "image".to_string(),
url: "https://example.com/img.png".to_string(),
},
};
let encoded = to_string(&message).unwrap();
// The key is the enum variant name: "WithAttachment".
// The value is the entire associated struct, serialized to JSON:
// {"text":"Check this out!","attachment":{"type_":"image","url":"https://example.com/img.png"}}
// ...and then that JSON string is percent-encoded.
let expected_value = "%7B%22text%22%3A%22Check%20this%20out%21%22%2C%22attachment%22%3A%7B%22type_%22%3A%22image%22%2C%22url%22%3A%22https%3A%2F%2Fexample.com%2Fimg.png%22%7D%7D";
let expected_string = format!("WithAttachment={}", expected_value);
assert_eq!(encoded, expected_string);
Modules§
Structs§
- Display
Serializer - A wrapper struct that implements
std::fmt::Display
for anyserde::Serialize
type. - Serializer
- The main serializer for the “Form + JSON” format.