Working with JSON in Rust

Rust uses the serde and serde_json crates for JSON serialization. These crates provide zero-cost abstractions and excellent performance for JSON handling.

Setup

Add these dependencies to your Cargo.toml:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Deserializing JSON

Use serde_json::from_str() to parse JSON into Rust types:

use serde::{Deserialize, Serialize};
use serde_json;

#[derive(Debug, Deserialize)]
struct User {
    name: String,
    age: u32,
    email: String,
    #[serde(default)]
    is_active: bool,
}

fn main() -> Result<(), serde_json::Error> {
    let json_str = r#"
    {
        "name": "John",
        "age": 30,
        "email": "john@example.com",
        "is_active": true
    }
    "#;

    let user: User = serde_json::from_str(json_str)?;

    println!("Name: {}", user.name);
    println!("Age: {}", user.age);
    println!("Active: {}", user.is_active);

    Ok(())
}

Serializing to JSON

Use serde_json::to_string() to convert Rust values to JSON:

use serde::{Deserialize, Serialize};
use serde_json;

#[derive(Debug, Serialize)]
struct User {
    name: String,
    age: u32,
    hobbies: Vec,
    is_active: bool,
}

fn main() -> Result<(), serde_json::Error> {
    let user = User {
        name: String::from("Jane"),
        age: 25,
        hobbies: vec![String::from("reading"), String::from("coding")],
        is_active: true,
    };

    // Compact JSON
    let json = serde_json::to_string(&user)?;
    println!("{}", json);

    // Pretty print
    let pretty_json = serde_json::to_string_pretty(&user)?;
    println!("{}", pretty_json);

    Ok(())
}

JSON Validation

use serde_json::{self, Value};

fn is_valid_json(s: &str) -> bool {
    serde_json::from_str::(s).is_ok()
}

struct ValidationResult {
    valid: bool,
    error: Option,
    json_type: Option,
}

fn validate_json(s: &str) -> ValidationResult {
    match serde_json::from_str::(s) {
        Ok(value) => {
            let json_type = match &value {
                Value::Object(_) => "object",
                Value::Array(_) => "array",
                Value::String(_) => "string",
                Value::Number(_) => "number",
                Value::Bool(_) => "boolean",
                Value::Null => "null",
            };

            ValidationResult {
                valid: true,
                error: None,
                json_type: Some(json_type.to_string()),
            }
        }
        Err(e) => ValidationResult {
            valid: false,
            error: Some(e.to_string()),
            json_type: None,
        },
    }
}

fn main() {
    println!("{}", is_valid_json(r#"{"name": "John"}"#)); // true
    println!("{}", is_valid_json("{invalid}"));           // false
}

Serde Attributes

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct User {
    // Rename field in JSON
    #[serde(rename = "user_name")]
    name: String,

    // Skip serializing
    #[serde(skip_serializing)]
    password: String,

    // Skip if None
    #[serde(skip_serializing_if = "Option::is_none")]
    middle_name: Option,

    // Default value
    #[serde(default)]
    score: i32,
}

Best Practices