Rust's Serde: Taming JSON with Types
Serde JSON translates between human-readable JSON text and native Rust structs, acting as a bilingual interpreter for your data. Use it for web APIs or config files.
WHY IT EXISTS: Applications need to communicate using standard formats like JSON, which is just text. Rust, with its strong type system, needs a safe and efficient way to convert this text into its own data structures to work with it, and then convert it back to text to send out. Serde provides this robust translation layer.
THE MENTAL MODEL: Think of Serde as a contract enforcer for your data. You define a Rust struct that represents the "contract" for the JSON you expect. When JSON arrives, Serde tries to fit the data into your struct. If it matches, you get a native Rust type you can work with safely. If it doesn't, you get a clear, compile-time or runtime error, preventing bad data from corrupting your program.
HOW IT WORKS: Serde JSON offers two primary modes. First, for strongly-typed data, you add #[derive(Serialize, Deserialize)] to a Rust struct. Serialize converts the struct into a JSON string. Deserialize parses a JSON string into an instance of the struct. Second, for untyped or unknown data, you can parse JSON into a serde_json::Value enum. This generic structure holds any valid JSON, which you can then inspect dynamically using index access like my_value["key"].
WHEN TO USE IT: Use the strongly-typed approach (structs with derive) whenever you know the structure of the JSON data, like for your application's API endpoints or configuration files. This is the most common and safest use case. Use the untyped Value enum when you need to handle arbitrary JSON, inspect a small part of a large document, or modify JSON without knowing its full structure.
WHEN NOT TO USE IT: Avoid the untyped Value approach for data with a known, stable structure. Relying on string keys for access (e.g., v["nmae"]) is fragile because a simple typo becomes a runtime logic error that silently returns a null value, not a compile-time error. For hyper-performance-critical paths where JSON parsing is too slow, consider binary formats like Protocol Buffers or MessagePack, which Serde also supports.
ONE CANONICAL EXAMPLE: To parse JSON into a type-safe struct, first define the struct and derive Deserialize. For a struct Person { name: String, age: u8 }, you would add #[derive(Deserialize)] above it. Then, given a JSON string like let data = r#"{ "name": "John Doe", "age": 43 }"#;, you can parse it with let p: Person = serde_json::from_str(data).unwrap();. This gives you a native Person instance, and you can access its fields directly, like p.name.
Read the original → docs.rs
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.