Introdução: Por que JSON é importante para o desenvolvedor Rust
JSON (JavaScript Object Notation) continua sendo um dos formatos de troca de dados mais populares no desenvolvimento web, microsserviços e APIs. Para a linguagem Rust, que está ganhando popularidade rapidamente devido ao seu desempenho e segurança, trabalhar com JSON é uma tarefa criticamente importante. Seja você um desenvolvedor backend usando Actix ou Rocket, escrevendo uma CLI-utility ou trabalhando com web sockets — a habilidade de fazer parse e serializar JSON em Rust será certamente útil.
Neste artigo, vamos explorar como trabalhar eficientemente com JSON em Rust, usando o ecossistema padrão de crates serde e serde_json. Você aprenderá como converter estruturas de dados para JSON e vice-versa, tratar erros e trabalhar com dados dinâmicos.
Fundamentos: Instalação e adição de dependências
Para trabalhar com JSON em Rust, utiliza-se o poderoso framework de serialização Serde e sua implementação para JSON — o crate serde_json. Para começar, adicione-os ao seu Cargo.toml:
[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"A flag features = ["derive"] permite usar as macros #[derive(Serialize, Deserialize)], o que simplifica significativamente o código.
Parse básico de uma string JSON
A maneira mais simples de começar é fazer o parse de uma string JSON para o tipo universal serde_json::Value. Isso é análogo ao serde_json::Value em Python ou ao object em 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("Erro ao fazer parse do JSON"); println!("Nome: {}", parsed["name"]); println!("Ano: {}", parsed["year"]); println!("Primeira feature: {}", parsed["features"][0]);}O tipo Value pode ser: Null, Bool, Number, String, Array ou Object. Isso é conveniente para prototipagem, mas para código de produção é melhor usar tipagem estrita.
Serialização e desserialização de estruturas
A principal força do Serde é a conversão automática entre estruturas Rust e JSON. Vejamos um exemplo:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]struct User { id: u32, name: String, email: String, active: bool,}
fn main() { // Desserialização (JSON -> Rust) let json_str = r#"{"id":1,"name":"Alexey","email":"alex@example.com","active":true}"#; let user: User = serde_json::from_str(json_str).unwrap(); println!("Usuário: {:?}", user);
// Serialização (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);}Observe o to_string_pretty — ele formata o JSON com indentação para legibilidade. Para produção, use to_string (sem espaços extras).
Trabalhando com estruturas aninhadas
JSON frequentemente contém objetos e arrays aninhados. O Serde lida com isso facilmente:
#[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": [```