JSON Processing in Rust: serde_json Library for Educational Website

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

JSON Processing in Rust: Complete Guide with serde_json



JSON (JavaScript Object Notation) is one of the most popular data exchange formats in web development. In Rust, JSON processing is done using the powerful serde_json library, which is part of the Serde ecosystem — a framework for serializing and deserializing data structures. In this article, we will thoroughly examine how to work with JSON in Rust: from installation to complex examples with nested structures.



Installation and Setup



To get started, add the dependencies to the Cargo.toml file:



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


The serde library provides the #[derive(Serialize, Deserialize)] macros, and serde_json handles converting data to and from JSON.



Basic Serialization and Deserialization



Let's look at a simple example: create a User struct and learn how to convert it to JSON and back.



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

#[derive(Debug, Serialize, Deserialize)]struct User { name: String, age: u8, email: String,}

fn main() { // Create an instance of the struct let user = User { name: "Alexey".to_string(), age: 30, email: "alex@example.com".to_string(), };

// Serialize to JSON string let json_string = serde_json::to_string(&user).unwrap(); println!("JSON: {}", json_string);

// Deserialize from JSON back to struct let deserialized_user: User = serde_json::from_str(&json_string).unwrap(); println!("Deserialized: {:?}", deserialized_user);}


Output:

JSON: {"name":"Alexey","age":30,"email":"alex@example.com"}Deserialized: User { name: "Alexey", age: 30, email: "alex@example.com" }


Working with Nested Structures



JSON often contains nested objects and arrays. Rust makes it easy to model such structures:



#[derive(Debug, Serialize, Deserialize)]struct Address {    city: String,    street: String,    house: u16,}

#[derive(Debug, Serialize, Deserialize)]struct Person { name: String, age: u8, address: Address, hobbies: Vec<String>,}

fn main() { let person = Person { name: "Maria".to_string(), age: 25, address: Address { city: "Moscow".to_string(), street: "Tverskaya".to_string(), house: 10, }, hobbies: vec!["reading".to_string(), "sports".to_string()], };

// Pretty-printed JSON output with indentation let pretty_json = serde_json::to_string_pretty(&person).unwrap(); println!("{}", pretty_json);}


Output:

{  "name": "Maria",  "age": 25,  "address": {    "city": "Moscow",    "street": "Tverskaya",    "house": 10  },  "hobbies": [    "reading",    "sports"  ]}


Error Handling and Optional Fields



In real projects, data may be incomplete. Rust offers elegant ways to handle such situations:



  • Option<T> — for optional fields
  • Result<T, E> — for handling parsing errors
  • Serde attributes — for customizing serialization behavior


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

#[derive(Debug, Serialize, Deserialize)]struct Product { name: String, price: f64, #[serde(default)] // Default value if field is missing description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] // Skip if None discount:

Recommendations