JSON to Rust
Gere structs Rust com derives serde Deserialize a partir de uma amostra JSON.
Entrada JSON
Código gerado
Digite JSON à esquerda para gerar um tipo a partir dele.
O que é JSON to Rust?
Um conversor de JSON para Rust gera as definições de struct necessárias para desserializar um payload JSON com serde, o crate que praticamente todo projeto Rust usa para isso. Rust não tem um tipo de objeto dinâmico como fallback, então consumir uma API significa declarar a forma exata de antemão: uma struct por objeto, um tipo concreto por campo e um #[derive(Deserialize)] em cada uma, para que o serde gere a implementação de parsing em tempo de compilação. Fazer isso à mão para uma resposta profundamente aninhada é lento e repetitivo, e o compilador rejeitará tudo por causa de um único tipo divergente. Este gerador produz todas as structs em ordem de dependência com os atributos de derive já anexados, para que você possa colar o resultado num módulo e o serde_json::from_str funcione imediatamente. Os nomes de campo também são convertidos automaticamente para o snake_case idiomático de Rust, e sempre que isso difere da chave JSON original — o que acontecerá para praticamente qualquer payload camelCase — um atributo `#[serde(rename = "...")]` é gerado naquele campo exato, para que você nunca precise adicionar atributos de renomeação manualmente.
Como usar JSON to Rust
- Cole uma resposta JSON representativa no painel esquerdo — os campos das structs espelham exatamente as chaves presentes naquela amostra.
- Defina um nome de struct raiz acima da saída (o padrão é "Root"); cada objeto aninhado se torna sua própria struct, nomeada pela chave que o contém.
- Adicione serde ao Cargo.toml com a feature derive (`serde = { version = "1", features = ["derive"] }`) mais o serde_json, depois cole as structs.
- Alterne o seletor de linguagem acima da saída para gerar a mesma forma como uma struct Go ou um tipo TypeScript.
Exemplos
Objeto plano com derive Deserialize
Entrada
{"id": 1, "name": "Ada", "active": true}
Saída
use serde::Deserialize; #[derive(Debug, Deserialize)] pub struct Root { pub id: i64, pub name: String, pub active: bool, }
Objeto aninhado se torna sua própria struct
Entrada
{"user": {"id": 1, "name": "Ada", "roles": ["admin"]}}
Saída
use serde::Deserialize; #[derive(Debug, Deserialize)] pub struct User { pub id: i64, pub name: String, pub roles: Vec<String>, } #[derive(Debug, Deserialize)] pub struct Root { pub user: User, }
Chave camelCase renomeada automaticamente para snake_case
Entrada
{"userId": 1, "firstName": "Ada"}
Saída
use serde::Deserialize; #[derive(Debug, Deserialize)] pub struct Root { #[serde(rename = "userId")] pub user_id: i64, #[serde(rename = "firstName")] pub first_name: String, }
Erros comuns
- Esquecer a feature derive no serde do Cargo.toml, o que produz um erro de resolução de macro que não aponta obviamente para a feature faltando.
- Deixar todo campo como não-Option quando a API às vezes omite um — o serde então falha a desserialização inteira em tempo de execução, em vez de deixar apenas aquele campo vazio.
- Adicionar seu próprio atributo de contêiner #[serde(rename_all = "camelCase")] por cima das structs geradas — é redundante, já que cada campo que precisa já carrega seu próprio #[serde(rename = "...")].
- Tratar todo campo serde_json::Value como algo bom para deixar como está — compila, mas você ainda precisa fazer match manualmente para extrair um valor utilizável; é um sinal de que a amostra não fixou o tipo daquele campo, não um resultado pronto.
- Marcar um campo como Option<T> só porque o JSON tecnicamente permite null em qualquer lugar, e não porque a amostra de fato o mostrou ausente ou null — envolver todo campo em Option<T> sem necessidade torna um valor genuinamente ausente mais difícil de notar depois.
Por que usar esta ferramenta
- Emite os atributos #[derive(Debug, Deserialize)] e o import de serde, para que a saída compile como está, sem precisar de boilerplate adicional.
- Declara as structs aninhadas em ordem de dependência, para que o arquivo compile de cima a baixo sem reordenação manual.
- Roda inteiramente no cliente, então uma resposta usada para gerar essas structs nunca sai da sua máquina antes que uma única linha chegue ao Cargo.
- Converte todo campo para o snake_case idiomático e anexa um #[serde(rename = "...")] por campo onde quer que ele difira da chave de origem, então um payload camelCase compila sem você mexer nos atributos de nomeação do serde.
- Recorre a serde_json::Value apenas onde um tipo concreto genuinamente não pode ser fixado — uma amostra só com null, ou um array misturando um inteiro e um float para a mesma chave — em vez de adivinhar errado um primitivo silenciosamente.