Introduction : Pourquoi JSON est important pour le développeur Rust
JSON (JavaScript Object Notation) reste l'un des formats d'échange de données les plus populaires dans le développement web, les microservices et les API. Pour le langage Rust, qui gagne rapidement en popularité grâce à ses performances et sa sécurité, travailler avec JSON est une tâche cruciale. Que vous soyez développeur backend sur Actix ou Rocket, que vous écriviez un utilitaire CLI ou que vous travailliez avec des websockets — savoir parser et sérialiser du JSON en Rust vous sera certainement utile.
Dans cet article, nous allons voir comment travailler efficacement avec JSON en Rust, en utilisant l'écosystème standard des crates serde et serde_json. Vous apprendrez à convertir des structures de données en JSON et vice versa, à gérer les erreurs et à travailler avec des données dynamiques.
Les bases : Installation et ajout des dépendances
Pour travailler avec JSON en Rust, on utilise le puissant framework de sérialisation Serde et son implémentation pour JSON — la crate serde_json. Pour commencer, ajoutez-les dans votre Cargo.toml :
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Le flag features = ["derive"] permet d'utiliser les macros #[derive(Serialize, Deserialize)], ce qui simplifie considérablement le code.
Parsing basique d'une chaîne JSON
La façon la plus simple de commencer est de parser une chaîne JSON dans le type universel serde_json::Value. C'est l'équivalent de serde_json::Value en Python ou de object en JavaScript :
use serde_json::Value;
fn main() {
let data = r#"
{
"name": "Rust",
"year": 2015,
"features": ["safe", "fast", "concurrent"]
}"#;
let parsed: Value = serde_json::from_str(data).expect("Erreur de parsing JSON");
println!("Nom : {}", parsed["name"]);
println!("Année : {}", parsed["year"]);
println!("Première fonctionnalité : {}", parsed["features"][0]);
}
Le type Value peut être : Null, Bool, Number, String, Array ou Object. C'est pratique pour le prototypage, mais pour du code de production, il est préférable d'utiliser un typage strict.
Sérialisation et désérialisation de structures
La force principale de Serde est la conversion automatique entre les structures Rust et le JSON. Voyons cela avec un exemple :
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
email: String,
active: bool,
}
fn main() {
// Désérialisation (JSON -> Rust)
let json_str = r#"{"id":1,"name":"Alexeï","email":"alex@example.com","active":true}"#;
let user: User = serde_json::from_str(json_str).unwrap();
println!("Utilisateur : {:?}", user);
// Sérialisation (Rust -> JSON)
let new_user = User {
id: 2,
name: String::from("Maria"),
email: String::from("maria@example.com"),
active: false,
};
let json_output = serde_json::to_string_pretty(&new_user).unwrap();
println!("JSON :{}", json_output);
}
Notez l'utilisation de to_string_pretty — il formate le JSON avec des indentations pour la lisibilité. Pour la production, utilisez to_string (sans espaces superflus).
Travail avec des structures imbriquées
Le JSON contient souvent des objets et des tableaux imbriqués. Serde gère cela facilement :
#[derive(Serialize, Deserialize)]
struct Project {
name: String,
languages: Vec<String>,
contributors: Vec<Contributor>,
}
#[derive(Serialize, Deserialize)]
struct Contributor {
username: String,
contributions: u32,
}
fn main() {
let project_json = r#"
{
"name": "Serde",
"languages": ["Rust", "Python", "C++"],
"contributors": [
```