Why JSON is Important
JSON is commonly used in APIs, configuration files and data storage because it is:
- Lightweight: Small and easy to parse.
- Readable: Human-friendly text format.
- Language-Agnostic: Works with many programming languages.
Setting Up Serde for JSON Handling
Add the following dependencies to your Cargo.toml file:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
- serde: Core library for serialization and deserialization.
- serde_json: JSON-specific library for working with JSON data.
Run the following command to build your project with the dependencies:
cargo build
1. Parsing JSON Strings into Rust Structures
Example: Parse JSON into a Struct
use serde::Deserialize;
use serde_json;
#[derive(Deserialize, Debug)]
struct User {
name: String,
age: u8,
email: String,
}
fn main() {
let json_data = r#"{"name": "Alice", "age": 30, "email": "alice@example.com"}"#;
let user: User = serde_json::from_str(json_data).expect("Failed to parse JSON");
println!("Parsed User: {:?}", user);
}
Output:
Parsed User: User { name: "Alice", age: 30, email: "alice@example.com" }
Explanation:
- The #[derive(Deserialize)] macro enables parsing JSON into the
User
struct. - serde_json::from_str converts the JSON string into the Rust struct.
2. Serializing Rust Structures into JSON Strings
Example: Convert a Struct into JSON
use serde::Serialize;
use serde_json;
#[derive(Serialize)]
struct User {
name: String,
age: u8,
email: String,
}
fn main() {
let user = User {
name: String::from("Bob"),
age: 25,
email: String::from("bob@example.com"),
};
let json_data = serde_json::to_string(&user).expect("Failed to convert to JSON");
println!("Serialized JSON: {}", json_data);
}
Output:
Serialized JSON: {"name":"Bob","age":25,"email":"bob@example.com"}
Explanation:
- The #[derive(Serialize)] macro enables the struct to be converted into JSON.
- serde_json::to_string creates the JSON string.
3. Parsing JSON Dynamically
For cases where you don’t know the structure of the JSON in advance, you can use serde_json::Value.
Example: Parse JSON Dynamically
use serde_json::{Value};
fn main() {
let json_data = r#"{"name": "Charlie", "age": 35, "skills": ["Rust", "Python"]}"#;
let parsed: Value = serde_json::from_str(json_data).expect("Failed to parse JSON");
println!("Name: {}", parsed["name"]);
println!("Age: {}", parsed["age"]);
println!("Skills: {:?}", parsed["skills"]);
}
Output:
Name: Charlie
Age: 35
Skills: ["Rust", "Python"]
Explanation:
- serde_json::Value is a flexible type that can represent any JSON value (e.g., strings, numbers, arrays).
- You can access fields using index syntax (parsed[“key”]).
4. Modifying JSON Data
You can modify JSON values dynamically when using serde_json::Value.
Example: Modify JSON
use serde_json::{Value, json};
fn main() {
let mut parsed: Value = json!({
"name": "Diana",
"age": 40,
"skills": ["JavaScript", "TypeScript"]
});
parsed["age"] = Value::from(41);
parsed["skills"].as_array_mut().unwrap().push(Value::from("Rust"));
println!("Modified JSON: {}", parsed);
}
Output:
Modified JSON: {"name":"Diana","age":41,"skills":["JavaScript","TypeScript","Rust"]}
Explanation:
- Use Value::from() to create new values.
- Use .as_array_mut() to modify arrays.
5. Error Handling in JSON Parsing
Rust enforces error handling, making your code robust. Use Result to handle JSON parsing errors.
Example: Handling Errors
use serde_json;
fn main() {
let invalid_json = r#"{"name": "Eve", "age": "thirty"}"#;
match serde_json::from_str::<serde_json::Value>(invalid_json) {
Ok(parsed) => println!("Parsed JSON: {}", parsed),
Err(e) => println!("Error parsing JSON: {}", e),
}
}
Output:
Error parsing JSON: invalid type: string "thirty", expected u64 at line 1 column 27
6. JSON File Handling
Example: Read JSON from a File
use serde::Deserialize;
use std::fs;
#[derive(Deserialize, Debug)]
struct Config {
app_name: String,
version: String,
debug: bool,
}
fn main() {
let json_data = fs::read_to_string("config.json").expect("Failed to read file");
let config: Config = serde_json::from_str(&json_data).expect("Failed to parse JSON");
println!("{:?}", config);
}
Explanation:
- Use fs::read_to_string to load the JSON file.
- Deserialize the file content using serde_json::from_str.
7. Writing JSON to a File
Example: Write JSON to a File
use serde::Serialize;
use std::fs;
#[derive(Serialize)]
struct Config {
app_name: String,
version: String,
debug: bool,
}
fn main() {
let config = Config {
app_name: String::from("MyApp"),
version: String::from("1.0.0"),
debug: true,
};
let json_data = serde_json::to_string(&config).expect("Failed to serialize JSON");
fs::write("output.json", json_data).expect("Failed to write file");
println!("JSON written to file!");
}
Common JSON Handling Functions
Function | Description |
---|---|
serde_json::to_string() | Serializes Rust structs to JSON strings. |
serde_json::from_str() | Deserializes JSON strings into Rust structs. |
serde_json::Value | Represents dynamic JSON data. |
serde_json::to_writer() | Writes JSON directly to an output stream. |