Introduction to Working with JSON in Rust
JSON (JavaScript Object Notation) is one of the most popular data exchange formats in web development, configuration files, and APIs. If you are learning Rust and want to learn how to work effectively with JSON, this article is for you. We will look at the main libraries, the principles of parsing and serialization, and also go through practical code examples.
In Rust, the ecosystem for working with JSON is built around the serde crate — a powerful framework for data serialization and deserialization. Together with serde_json, it allows you to easily convert data structures to and from JSON. Let's figure out how it works.
Installing and Configuring Dependencies
First, let's create a new project and add the necessary dependencies to the Cargo.toml file:
[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"The serde crate provides the #[derive(Serialize, Deserialize)] macros, which automatically implement the necessary traits for your structures. serde_json is responsible for directly working with the JSON format.
Parsing JSON: From String to Structure
Suppose we have a JSON string with user information. We want to convert it into a typed Rust structure. Here's how it's done:
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]struct User { name: String, age: u32, email: String, is_active: bool,}
fn main() { let json_data = r#" { "name": "Alexey", "age": 28, "email": "alex@example.com", "is_active": true } "#;
// Parsing JSON into a structure let user: User = serde_json::from_str(json_data).expect("JSON parsing error"); println!("User: {:?}", user); println!("Name: {}", user.name); println!("Age: {}", user.age);}Notice the attribute #[derive(Debug, Deserialize, Serialize)]. Debug allows you to print the structure to the console, while Deserialize and Serialize enable converting data to and from JSON.
Handling Nested Objects
JSON often contains nested objects. Let's look at an example with a user's address:
#[derive(Debug, Deserialize, Serialize)]struct Address { city: String, street: String, zip_code: String,}
#[derive(Debug, Deserialize, Serialize)]struct User { name: String, age: u32, address: Address,}
fn main() { let json_data = r#" { "name": "Maria", "age": 32, "address": { "city": "Moscow", "street": "Tverskaya, 15", "zip_code": "101000" } } "#;
let user: User = serde_json::from_str(json_data).unwrap(); println!("City: {}", user.address.city);}Working with JSON Arrays
Arrays in JSON are converted to Vec or other Rust collections:
use serde::Deserialize;
#[derive(Debug, Deserialize)]struct Product { id: u32, name: String, price: f64,}
fn main() { let json_array = r#" [ {"id": 1, "name": "Laptop", "price": 75000.50}, {"id": 2, "name": "Mouse", "price": 1500.00}, {"id": 3, "name": "Keyboard", "price": 3500.00} ] "#;
let products: Vec<Product> = serde_json::from_str(json_array).unwrap(); for product in &products { println!("{}: {} rub.", product.name, product.price); }}Serialization: From Structure to JSON
The reverse process — converting a Rust structure into a JSON string. This is called s