Introdução
JSON (JavaScript Object Notation) é o formato de dados mais usado para APIs web, configuração e troca de dados entre sistemas. Em Zig, a biblioteca padrão std.json oferece ferramentas poderosas para parsear JSON de forma tipada ou dinâmica.
Nesta receita, você aprenderá as diversas formas de parsear JSON em Zig, desde parsing simples até cenários complexos com dados aninhados.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
- Familiaridade com structs e enums
Parsing Tipado (Recomendado)
A forma mais segura: defina uma struct que espelha o JSON esperado:
const std = @import("std");
const Usuario = struct {
nome: []const u8,
email: []const u8,
idade: u32,
ativo: bool,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_str =
\\{
\\ "nome": "Maria Silva",
\\ "email": "maria@exemplo.com",
\\ "idade": 28,
\\ "ativo": true
\\}
;
const parsed = try std.json.parseFromSlice(
Usuario,
allocator,
json_str,
.{},
);
defer parsed.deinit();
const user = parsed.value;
std.debug.print("Nome: {s}\n", .{user.nome});
std.debug.print("Email: {s}\n", .{user.email});
std.debug.print("Idade: {d}\n", .{user.idade});
std.debug.print("Ativo: {}\n", .{user.ativo});
}
Saída esperada
Nome: Maria Silva
Email: maria@exemplo.com
Idade: 28
Ativo: true
Parsing com Campos Opcionais
Use tipos opcionais para campos que podem não existir no JSON:
const std = @import("std");
const Produto = struct {
nome: []const u8,
preco: f64,
descricao: ?[]const u8 = null,
estoque: ?u32 = null,
tags: ?[]const []const u8 = null,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// JSON sem campos opcionais
const json_minimal =
\\{"nome": "Teclado Mecânico", "preco": 299.90}
;
const p1 = try std.json.parseFromSlice(Produto, allocator, json_minimal, .{
.ignore_unknown_fields = true,
});
defer p1.deinit();
std.debug.print("Produto: {s}\n", .{p1.value.nome});
std.debug.print("Preço: {d:.2}\n", .{p1.value.preco});
std.debug.print("Descrição: {s}\n", .{p1.value.descricao orelse "N/A"});
// JSON completo
const json_full =
\\{
\\ "nome": "Mouse Gamer",
\\ "preco": 159.90,
\\ "descricao": "Mouse com 6 botões programáveis",
\\ "estoque": 42,
\\ "tags": ["gamer", "periférico", "rgb"]
\\}
;
const p2 = try std.json.parseFromSlice(Produto, allocator, json_full, .{
.ignore_unknown_fields = true,
});
defer p2.deinit();
std.debug.print("\nProduto: {s}\n", .{p2.value.nome});
std.debug.print("Descrição: {s}\n", .{p2.value.descricao.?});
std.debug.print("Estoque: {d}\n", .{p2.value.estoque.?});
if (p2.value.tags) |tags| {
std.debug.print("Tags: ", .{});
for (tags, 0..) |tag, i| {
if (i > 0) std.debug.print(", ", .{});
std.debug.print("{s}", .{tag});
}
std.debug.print("\n", .{});
}
}
Parsing com Ignorar Campos Desconhecidos
Quando o JSON contém campos que você não precisa:
const std = @import("std");
const Resumo = struct {
id: u64,
titulo: []const u8,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// JSON com muitos campos que não precisamos
const json_str =
\\{
\\ "id": 12345,
\\ "titulo": "Artigo sobre Zig",
\\ "autor": "João",
\\ "data_publicacao": "2026-02-21",
\\ "conteudo": "Lorem ipsum...",
\\ "comentarios": 42,
\\ "visualizacoes": 1500
\\}
;
// ignore_unknown_fields permite ignorar campos extras
const parsed = try std.json.parseFromSlice(Resumo, allocator, json_str, .{
.ignore_unknown_fields = true,
});
defer parsed.deinit();
std.debug.print("ID: {d}\n", .{parsed.value.id});
std.debug.print("Título: {s}\n", .{parsed.value.titulo});
}
Parsing Dinâmico (sem tipo)
Quando a estrutura JSON é desconhecida em tempo de compilação:
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_str =
\\{
\\ "nome": "Zig Brasil",
\\ "membros": 1500,
\\ "ativo": true,
\\ "linguagens": ["zig", "c", "c++"],
\\ "contato": {
\\ "email": "contato@zigbrasil.com",
\\ "site": "https://zigbrasil.com"
\\ }
\\}
;
const parsed = try std.json.parseFromSlice(
std.json.Value,
allocator,
json_str,
.{},
);
defer parsed.deinit();
const root = parsed.value.object;
// Acessar string
const nome = root.get("nome").?.string;
std.debug.print("Nome: {s}\n", .{nome});
// Acessar número
const membros = root.get("membros").?.integer;
std.debug.print("Membros: {d}\n", .{membros});
// Acessar boolean
const ativo = root.get("ativo").?.bool;
std.debug.print("Ativo: {}\n", .{ativo});
// Acessar array
const linguagens = root.get("linguagens").?.array;
std.debug.print("Linguagens: ", .{});
for (linguagens.items, 0..) |item, i| {
if (i > 0) std.debug.print(", ", .{});
std.debug.print("{s}", .{item.string});
}
std.debug.print("\n", .{});
// Acessar objeto aninhado
const contato = root.get("contato").?.object;
const email = contato.get("email").?.string;
std.debug.print("Email: {s}\n", .{email});
}
Parsing de Array JSON
Parsear um array de objetos:
const std = @import("std");
const Tarefa = struct {
id: u64,
titulo: []const u8,
completa: bool,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_str =
\\[
\\ {"id": 1, "titulo": "Estudar Zig", "completa": true},
\\ {"id": 2, "titulo": "Criar projeto", "completa": false},
\\ {"id": 3, "titulo": "Escrever testes", "completa": false}
\\]
;
const parsed = try std.json.parseFromSlice(
[]Tarefa,
allocator,
json_str,
.{},
);
defer parsed.deinit();
const tarefas = parsed.value;
std.debug.print("Total de tarefas: {d}\n\n", .{tarefas.len});
for (tarefas) |tarefa| {
const status = if (tarefa.completa) "[x]" else "[ ]";
std.debug.print("{s} #{d}: {s}\n", .{ status, tarefa.id, tarefa.titulo });
}
}
Saída esperada
Total de tarefas: 3
[x] #1: Estudar Zig
[ ] #2: Criar projeto
[ ] #3: Escrever testes
Tratamento de Erros no Parsing
Trate erros de JSON malformado:
const std = @import("std");
const Config = struct {
porta: u16,
host: []const u8,
};
fn parseConfig(allocator: std.mem.Allocator, json_str: []const u8) !Config {
const parsed = std.json.parseFromSlice(Config, allocator, json_str, .{}) catch |err| {
switch (err) {
error.UnexpectedCharacter => {
std.debug.print("Erro: JSON contém caractere inesperado\n", .{});
return err;
},
error.InvalidNumber => {
std.debug.print("Erro: número inválido no JSON\n", .{});
return err;
},
else => {
std.debug.print("Erro ao parsear JSON: {}\n", .{err});
return err;
},
}
};
defer parsed.deinit();
// Copiar strings para que sobrevivam após deinit
const host = try allocator.dupe(u8, parsed.value.host);
return Config{
.porta = parsed.value.porta,
.host = host,
};
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// JSON válido
const valid = try parseConfig(allocator, "{\"porta\": 8080, \"host\": \"localhost\"}");
defer allocator.free(valid.host);
std.debug.print("Config: {s}:{d}\n", .{ valid.host, valid.porta });
// JSON inválido
_ = parseConfig(allocator, "{porta: 8080}") catch {
std.debug.print("Falha ao parsear JSON inválido (esperado)\n", .{});
};
}
Dicas e Boas Práticas
Prefira parsing tipado: Use structs quando a estrutura é conhecida. É mais seguro e performático.
Use
ignore_unknown_fields: Ao consumir APIs externas, ignore campos que você não precisa.Campos opcionais com valor padrão: Use
?T = nullpara campos que podem não existir.Libere memória: Sempre chame
parsed.deinit()para liberar a memória alocada pelo parser.Cuidado com strings: As strings do JSON parseado são referências ao buffer original ou à memória do parsed. Use
allocator.dupese precisar mantê-las apósdeinit().
Receitas Relacionadas
- Como gerar JSON em Zig - Serializar dados para JSON
- Como ler/escrever JSON em arquivos - Persistência de JSON
- Como fazer streaming de JSON em Zig - Parsing eficiente
- Como validar JSON em Zig - Validação de dados
- Como fazer requisições HTTP GET em Zig - Consumir APIs