Parse JSON em Rust

Aprenda como fazer parse de JSON em Rust com serde_json. Deserialização tipada, Value dinâmico, from_str, from_reader e tratamento de erros.

Parse JSON em Rust

A crate serde_json é a ferramenta padrão para trabalhar com JSON em Rust. Ela permite deserializar JSON tanto para structs tipadas quanto para valores dinâmicos, com excelente performance e segurança de tipos.

Dependências

Cargo.toml:

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

Parse básico com Value (dinâmico)

Para JSON de estrutura desconhecida ou variável, use serde_json::Value:

use serde_json::Value;

fn main() {
    let json_str = r#"
    {
        "nome": "Maria Silva",
        "idade": 30,
        "ativa": true,
        "endereco": {
            "cidade": "São Paulo",
            "estado": "SP"
        },
        "hobbies": ["leitura", "programação", "corrida"]
    }
    "#;

    // Parse para Value
    let valor: Value = serde_json::from_str(json_str).unwrap();

    // Acessar campos com indexação
    println!("Nome: {}", valor["nome"]);
    println!("Idade: {}", valor["idade"]);
    println!("Cidade: {}", valor["endereco"]["cidade"]);
    println!("Primeiro hobby: {}", valor["hobbies"][0]);

    // Acessar como tipos Rust
    if let Some(nome) = valor["nome"].as_str() {
        println!("Nome (str): {}", nome);
    }
    if let Some(idade) = valor["idade"].as_i64() {
        println!("Idade (i64): {}", idade);
    }
    if let Some(ativa) = valor["ativa"].as_bool() {
        println!("Ativa (bool): {}", ativa);
    }

    // Iterar sobre array
    if let Some(hobbies) = valor["hobbies"].as_array() {
        print!("Hobbies:");
        for hobby in hobbies {
            print!(" {}", hobby.as_str().unwrap_or("?"));
        }
        println!();
    }

    // Campo inexistente retorna Null (sem pânico)
    println!("Campo inexistente: {}", valor["nao_existe"]);
}

Saída:

Nome: "Maria Silva"
Idade: 30
Cidade: "São Paulo"
Primeiro hobby: "leitura"
Nome (str): Maria Silva
Idade (i64): 30
Ativa (bool): true
Hobbies: leitura programação corrida
Campo inexistente: null

Deserialização tipada com structs

A forma mais segura e idiomática — mapeie JSON para structs Rust:

use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Usuario {
    nome: String,
    idade: u32,
    email: String,
    #[serde(default)]
    ativo: bool,
    #[serde(rename = "dataCadastro")]
    data_cadastro: Option<String>,
}

fn main() {
    let json_str = r#"
    {
        "nome": "João Santos",
        "idade": 25,
        "email": "joao@exemplo.com",
        "ativo": true,
        "dataCadastro": "2026-01-15"
    }
    "#;

    // Deserializar para struct
    let usuario: Usuario = serde_json::from_str(json_str).unwrap();

    println!("Usuário: {:?}", usuario);
    println!("Nome: {}", usuario.nome);
    println!("Idade: {}", usuario.idade);
    println!("Cadastro: {}", usuario.data_cadastro.unwrap_or_default());

    // JSON sem campo opcional
    let json_parcial = r#"
    {
        "nome": "Ana Lima",
        "idade": 22,
        "email": "ana@exemplo.com"
    }
    "#;

    let usuario2: Usuario = serde_json::from_str(json_parcial).unwrap();
    println!("\nUsuário 2: {:?}", usuario2);
    println!("Ativo (padrão): {}", usuario2.ativo);
    println!("Data: {:?}", usuario2.data_cadastro);
}

Saída:

Usuário: Usuario { nome: "João Santos", idade: 25, email: "joao@exemplo.com", ativo: true, data_cadastro: Some("2026-01-15") }
Nome: João Santos
Idade: 25
Cadastro: 2026-01-15

Usuário 2: Usuario { nome: "Ana Lima", idade: 22, email: "ana@exemplo.com", ativo: false, data_cadastro: None }
Ativo (padrão): false
Data: None

Parse de array JSON

Deserialize arrays JSON para Vec<T>:

use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Tarefa {
    id: u32,
    titulo: String,
    concluida: bool,
}

fn main() {
    let json_array = r#"
    [
        {"id": 1, "titulo": "Aprender Rust", "concluida": true},
        {"id": 2, "titulo": "Criar API REST", "concluida": false},
        {"id": 3, "titulo": "Escrever testes", "concluida": false},
        {"id": 4, "titulo": "Deploy em produção", "concluida": false}
    ]
    "#;

    let tarefas: Vec<Tarefa> = serde_json::from_str(json_array).unwrap();

    println!("Total de tarefas: {}", tarefas.len());
    println!();

    for tarefa in &tarefas {
        let status = if tarefa.concluida { "[x]" } else { "[ ]" };
        println!("{} #{}: {}", status, tarefa.id, tarefa.titulo);
    }

    // Filtrar tarefas pendentes
    let pendentes: Vec<&Tarefa> = tarefas.iter()
        .filter(|t| !t.concluida)
        .collect();
    println!("\nPendentes: {}", pendentes.len());
}

Saída:

Total de tarefas: 4

[x] #1: Aprender Rust
[ ] #2: Criar API REST
[ ] #3: Escrever testes
[ ] #4: Deploy em produção

Pendentes: 3

Tratamento de erros no parse

Trate erros de deserialização de forma robusta:

use serde::Deserialize;
use serde_json;

#[derive(Debug, Deserialize)]
struct Config {
    host: String,
    porta: u16,
    debug: bool,
}

fn parse_config(json: &str) -> Result<Config, String> {
    serde_json::from_str(json)
        .map_err(|e| format!("Erro no JSON: {} (linha {}, coluna {})",
            e, e.line(), e.column()))
}

fn main() {
    // JSON válido
    let valido = r#"{"host": "localhost", "porta": 8080, "debug": true}"#;
    match parse_config(valido) {
        Ok(config) => println!("Config: {:?}", config),
        Err(e) => println!("Erro: {}", e),
    }

    // JSON com tipo errado
    let tipo_errado = r#"{"host": "localhost", "porta": "não_é_número", "debug": true}"#;
    match parse_config(tipo_errado) {
        Ok(config) => println!("Config: {:?}", config),
        Err(e) => println!("Erro: {}", e),
    }

    // JSON mal formado
    let mal_formado = r#"{"host": "localhost", porta: 8080}"#;
    match parse_config(mal_formado) {
        Ok(config) => println!("Config: {:?}", config),
        Err(e) => println!("Erro: {}", e),
    }

    // JSON com campo faltando
    let incompleto = r#"{"host": "localhost"}"#;
    match parse_config(incompleto) {
        Ok(config) => println!("Config: {:?}", config),
        Err(e) => println!("Erro: {}", e),
    }
}

Saída:

Config: Config { host: "localhost", porta: 8080, debug: true }
Erro: Erro no JSON: invalid type: string "não_é_número", expected u16 (linha 1, coluna 47)
Erro: Erro no JSON: key must be a string at line 1 column 25 (linha 1, coluna 25)
Erro: Erro no JSON: missing field `porta` at line 1 column 22 (linha 1, coluna 22)

Parse de JSON de arquivo

Leia e parse um arquivo JSON diretamente:

use serde::Deserialize;
use std::fs::File;
use std::io::BufReader;

#[derive(Debug, Deserialize)]
struct Dados {
    titulo: String,
    itens: Vec<String>,
}

fn main() {
    // Criar arquivo JSON de exemplo
    std::fs::write("dados.json", r#"
    {
        "titulo": "Minha Lista",
        "itens": ["Item 1", "Item 2", "Item 3"]
    }
    "#).unwrap();

    // Ler e parsear diretamente do arquivo
    let arquivo = File::open("dados.json").expect("Erro ao abrir arquivo");
    let leitor = BufReader::new(arquivo);
    let dados: Dados = serde_json::from_reader(leitor)
        .expect("Erro ao parsear JSON do arquivo");

    println!("Título: {}", dados.titulo);
    for item in &dados.itens {
        println!("  - {}", item);
    }
}

Saída:

Título: Minha Lista
  - Item 1
  - Item 2
  - Item 3

Construir JSON com json! macro

Crie valores JSON inline sem definir structs:

use serde_json::json;

fn main() {
    let nome = "Rust";
    let versao = 2026;

    let valor = json!({
        "linguagem": nome,
        "ano": versao,
        "caracteristicas": ["segura", "rápida", "concorrente"],
        "detalhes": {
            "tipagem": "estática",
            "paradigma": "multi-paradigma"
        }
    });

    // Pretty print
    let formatado = serde_json::to_string_pretty(&valor).unwrap();
    println!("{}", formatado);
}

Saída:

{
  "ano": 2026,
  "caracteristicas": [
    "segura",
    "rápida",
    "concorrente"
  ],
  "detalhes": {
    "paradigma": "multi-paradigma",
    "tipagem": "estática"
  },
  "linguagem": "Rust"
}

Veja também