| Crates.io | serde-metaform |
| lib.rs | serde-metaform |
| version | 1.0.1 |
| created_at | 2025-10-07 11:01:12.576729+00 |
| updated_at | 2025-10-09 09:55:08.941428+00 |
| description | Form encoder for Meta (Facebook/WhatsApp/Graph API) batch requests. Serializes values to JSON then URL-encodes them, matching Meta’s quirky request body format. |
| homepage | |
| repository | https://github.com/veecore/serde-metaform |
| max_upload_size | |
| id | 1871515 |
| size | 96,275 |
A high-performance serde serializer for the hybrid "Form + JSON" encoding format used by APIs like Meta’s (WhatsApp Business, Instagram Messaging, etc.).
⚠️ Warning: This is not a standard
application/x-www-form-urlencodedserializer. It produces a specialized encoding where values are JSON-encoded before being percent-encoded. Do not use this for ordinary HTML form submissions.
This format looks like a typical form payload (key=value&key2=value2), but each value is actually JSON.
This hybrid structure allows complex nested JSON to be transmitted in APIs that only accept form-like bodies.
Standard form encoding:
user_id=123&tags=rust&tags=serde
Form + JSON encoding:
user_id=123&
profile=%7B%22username%22%3A%22jdoe%22%2C%22tags%22%3A%5B%22rust%22%2C%22serde%22%5D%7D
The profile value above is the percent-encoded JSON string:
{"username":"jdoe","tags":["rust","serde"]}
serde_json::Value, no double parsing.serde Integration: Works out of the box with #[derive(Serialize)].whatsapp-business-rs.Add to your Cargo.toml:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_metaform = "1"
Then simply serialize your data:
use serde::Serialize;
use serde_metaform::to_string;
#[derive(Serialize)]
struct Message<'a> {
recipient: &'a str,
content: Content<'a>,
}
#[derive(Serialize)]
struct Content<'a> {
#[serde(rename = "type")]
message_type: &'a str,
text: &'a str,
buttons: Vec<Button<'a>>,
}
#[derive(Serialize)]
struct Button<'a> {
id: &'a str,
title: &'a str,
}
fn main() -> Result<(), serde_metaform::error::Error> {
let msg = Message {
recipient: "1234567890",
content: Content {
message_type: "interactive",
text: "Choose an option:",
buttons: vec![
Button { id: "opt1", title: "Option 1" },
Button { id: "opt2", title: "Option 2" },
],
},
};
let encoded = to_string(&msg)?;
println!("{encoded}");
// Output (simplified, actual output is percent-encoded):
// recipient=1234567890&
// content={"type":"interactive","text":"Choose an option:","buttons":[{"id":"opt1","title":"Option 1"},{"id":"opt2","title":"Option 2"}]}
Ok(())
}
serde_metaform was originally extracted from a production WhatsApp integration layer,
where JSON bodies were pre-built before conversion to the hybrid format.
This crate eliminates that two-step process.
| Benchmark | Description | Mean Time | Relative |
|---|---|---|---|
json_value |
struct → JSON Value → form | 35.5 µs | 1.00× |
json_pipeline |
struct → Bytes → form (old pipeline) | 23.6 µs | 1.5× faster |
from_struct |
struct → form (serde_metaform) |
14.0 µs | 2.53× faster |
Real-world WhatsApp payloads typically gain 35–45 % throughput improvement.
Licensed under either of:
at your option.