---
title: "Parsing JSON em Zig: Tutorial Completo com Exemplos Práticos"
url: "https://ziglang.com.br/tutoriais/parsing-json-zig/"
markdown_url: "https://ziglang.com.br/tutoriais/parsing-json-zig.MD"
description: "Aprenda a trabalhar com JSON em Zig: parse, serialize, e manipular dados JSON usando std.json. Tutorial completo com exemplos reais de APIs REST."
date: "2026-02-10"
author: ""
---

# Parsing JSON em Zig: Tutorial Completo com Exemplos Práticos

Aprenda a trabalhar com JSON em Zig: parse, serialize, e manipular dados JSON usando std.json. Tutorial completo com exemplos reais de APIs REST.


JSON é o formato de dados mais popular da web moderna. APIs REST, configurações, logs, e troca de dados entre sistemas — tudo usa JSON. Saber trabalhar com JSON é uma habilidade essencial para qualquer desenvolvedor Zig.

Neste tutorial completo, você vai aprender tudo sobre **parsing JSON em Zig** — desde o básico até casos avançados com APIs reais. Ao final, será capaz de consumir qualquer API JSON e criar seus próprios serviços.

## Por que JSON em Zig?

O Zig oferece um sistema de parsing JSON poderoso e eficiente através do módulo `std.json`:

| Característica | std.json Zig | Outras Linguagens |
|----------------|--------------|-------------------|
| **Zero allocations** | ✅ Possível | ⚠️ Raro |
| **Type safety** | ✅ Compile-time | ⚠️ Runtime |
| **Performance** | ✅ Nativa | Variável |
| **Streaming** | ✅ Suportado | ⚠️ Limitado |
| **Sem dependências** | ✅ Built-in | ❌ Precisa libs |

### Abordagens do std.json

1. **Structs tipadas** — Parse direto para structs (mais eficiente, type safe)
2. **Value dinâmico** — Trabalhe com JSON genérico (flexível, menos type safe)
3. **Streaming** — Parse grandes arquivos sem carregar tudo na memória

Vamos explorar cada uma.

## Pré-requisitos

Antes de começar:

1. **Zig instalado** (0.13.0+) — veja [Como Instalar o Zig](/tutoriais/como-instalar-zig/)
2. **Conhecimento básico de Zig** — structs, allocators, error handling
3. **Familiaridade com JSON** — objetos, arrays, tipos de dados

## Setup do Projeto

```bash
mkdir json-tutorial
cd json-tutorial
zig init
```

## Parte 1: Parsing JSON Básico

### 1.1 Parse para Struct (Mais Comum)

A forma mais eficiente de trabalhar com JSON é mapear diretamente para structs:

```zig
// src/main.zig
const std = @import("std");

// Struct que representa o JSON
const User = struct {
    id: u32,
    name: []const u8,
    email: []const u8,
    active: bool,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON de exemplo
    const json_str =
        \\{
        \\  "id": 1,
        \\  "name": "João Silva",
        \\  "email": "joao@exemplo.com",
        \\  "active": true
        \\}
    ;

    // Parse o JSON para a struct User
    const parsed = try std.json.parseFromSlice(
        User,
        allocator,
        json_str,
        .{}, // opções padrão
    );
    defer parsed.deinit(); // Libera memória

    // Acessa os dados
    const user = parsed.value;
    std.debug.print("ID: {d}\n", .{user.id});
    std.debug.print("Nome: {s}\n", .{user.name});
    std.debug.print("Email: {s}\n", .{user.email});
    std.debug.print("Ativo: {}\n", .{user.active});
}
```

Compile e execute:

```bash
zig build run
```

Saída:
```
ID: 1
Nome: João Silva
Email: joao@exemplo.com
Ativo: true
```

### 1.2 Parse de Arrays

JSON com arrays é igualmente simples:

```zig
const std = @import("std");

const Product = struct {
    id: u32,
    name: []const u8,
    price: f64,
    tags: []const []const u8, // Array de strings
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const json_str =
        \\[
        \\  {"id": 1, "name": "Notebook", "price": 4500.00, "tags": ["eletrônicos", "computadores"]},
        \\  {"id": 2, "name": "Mouse", "price": 89.90, "tags": ["eletrônicos", "acessórios"]},
        \\  {"id": 3, "name": "Teclado", "price": 199.00, "tags": ["eletrônicos"]}
        \\]
    ;

    const parsed = try std.json.parseFromSlice(
        []const Product,
        allocator,
        json_str,
        .{},
    );
    defer parsed.deinit();

    std.debug.print("Produtos encontrados: {d}\n\n", .{parsed.value.len});

    for (parsed.value) |product| {
        std.debug.print("📦 {s}\n", .{product.name});
        std.debug.print("   Preço: R$ {d:.2}\n", .{product.price});
        std.debug.print("   Tags: ", .{});
        for (product.tags) |tag| {
            std.debug.print("{s} ", .{tag});
        }
        std.debug.print("\n\n", .{});
    }
}
```

### 1.3 Campos Opcionais

Muitas APIs retornam campos que podem estar ausentes. Use `?T` para opcional:

```zig
const std = @import("std");

const Profile = struct {
    username: []const u8,
    bio: ?[]const u8,        // Pode ser null
    website: ?[]const u8,    // Pode ser null
    followers: u32,
    following: u32,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON com campos ausentes
    const json_str =
        \\{
        \\  "username": "maria_dev",
        \\  "bio": "Desenvolvedora Zig entusiasta",
        \\  "followers": 1500,
        \\  "following": 230
        \\}
    ;

    const parsed = try std.json.parseFromSlice(
        Profile,
        allocator,
        json_str,
        .{},
    );
    defer parsed.deinit();

    const profile = parsed.value;
    std.debug.print("👤 @{s}\n", .{profile.username});

    if (profile.bio) |bio| {
        std.debug.print("   Bio: {s}\n", .{bio});
    } else {
        std.debug.print("   Bio: (não informada)\n", .{});
    }

    if (profile.website) |site| {
        std.debug.print("   Site: {s}\n", .{site});
    } else {
        std.debug.print("   Site: (não informado)\n", .{});
    }

    std.debug.print("   Seguidores: {d} | Seguindo: {d}\n", .{
        profile.followers,
        profile.following,
    });
}
```

### 1.4 Mapeamento de Nomes

Quando o JSON usa convenção diferente (snake_case vs camelCase):

```zig
const std = @import("std");

const ApiResponse = struct {
    // Mapeia "user_id" no JSON para "user_id" na struct
    user_id: u32,
    // Mapeia "created_at" no JSON para "created_at" na struct
    created_at: []const u8,
    // Mapeia "isActive" no JSON para "is_active" na struct
    is_active: bool,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON com snake_case
    const json_str =
        \\{
        \\  "user_id": 42,
        \\  "created_at": "2026-02-10T14:30:00Z",
        \\  "is_active": true
        \\}
    ;

    // Use .allocate para mapear campos com nomes diferentes
    const parsed = try std.json.parseFromSlice(
        ApiResponse,
        allocator,
        json_str,
        .{
            .allocate = .alloc_always, // Necessário para strings
        },
    );
    defer parsed.deinit();

    const data = parsed.value;
    std.debug.print("User ID: {d}\n", .{data.user_id});
    std.debug.print("Created: {s}\n", .{data.created_at});
    std.debug.print("Active: {}\n", .{data.is_active});
}
```

## Parte 2: Serialização (Struct → JSON)

### 2.1 Serialize Struct para JSON

Converter dados para JSON é igualmente simples:

```zig
const std = @import("std");

const Task = struct {
    id: u32,
    title: []const u8,
    completed: bool,
    priority: []const u8,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const task = Task{
        .id = 1,
        .title = "Implementar parsing JSON",
        .completed = false,
        .priority = "high",
    };

    // Serializa para string JSON
    const json_str = try std.json.stringifyAlloc(allocator, task, .{});
    defer allocator.free(json_str);

    std.debug.print("JSON gerado:\n{s}\n", .{json_str});
}
```

Saída:
```json
{"id":1,"title":"Implementar parsing JSON","completed":false,"priority":"high"}
```

### 2.2 Pretty Print (JSON Formatado)

Para output legível, use `.whitespace`:

```zig
const std = @import("std");

const Project = struct {
    name: []const u8,
    version: []const u8,
    dependencies: []const []const u8,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const project = Project{
        .name = "meu-app-zig",
        .version = "1.0.0",
        .dependencies = &.{ "zig-clap", "zig-json" },
    };

    // Pretty print com indentação
    const json_str = try std.json.stringifyAlloc(
        allocator,
        project,
        .{ .whitespace = .indent_2 },
    );
    defer allocator.free(json_str);

    std.debug.print("{s}\n", .{json_str});
}
```

Saída:
```json
{
  "name": "meu-app-zig",
  "version": "1.0.0",
  "dependencies": [
    "zig-clap",
    "zig-json"
  ]
}
```

### 2.3 Escrever JSON em Arquivo

```zig
const std = @import("std");

const Config = struct {
    server_host: []const u8,
    server_port: u16,
    debug_mode: bool,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const config = Config{
        .server_host = "localhost",
        .server_port = 8080,
        .debug_mode = true,
    };

    // Cria arquivo
    const file = try std.fs.cwd().createFile("config.json", .{});
    defer file.close();

    // Escreve JSON formatado no arquivo
    try std.json.stringify(config, .{ .whitespace = .indent_2 }, file.writer());

    std.debug.print("✅ Configuração salva em config.json\n", .{});
}
```

## Parte 3: JSON Dinâmico (std.json.Value)

Quando você não conhece a estrutura do JSON antecipadamente, use `std.json.Value`:

### 3.1 Trabalhando com JSON Genérico

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const json_str =
        \\{
        \\  "status": "success",
        \\  "data": {
        \\    "users": [
        \\      {"id": 1, "name": "Alice"},
        \\      {"id": 2, "name": "Bob"}
        \\    ],
        \\    "total": 2
        \\  },
        \\  "meta": {
        \\    "page": 1,
        \\    "per_page": 10
        \\  }
        \\}
    ;

    // Parse para Value (JSON dinâmico)
    const parsed = try std.json.parseFromSlice(
        std.json.Value,
        allocator,
        json_str,
        .{},
    );
    defer parsed.deinit();

    const root = parsed.value;

    // Acessa campos dinamicamente
    const status = root.object.get("status").?.string;
    std.debug.print("Status: {s}\n", .{status});

    const data = root.object.get("data").?;
    const total = data.object.get("total").?.integer;
    std.debug.print("Total de usuários: {d}\n", .{total});

    const users = data.object.get("users").?.array;
    std.debug.print("Usuários:\n", .{});
    for (users.items) |user| {
        const id = user.object.get("id").?.integer;
        const name = user.object.get("name").?.string;
        std.debug.print("  - {d}: {s}\n", .{ id, name });
    }
}
```

### 3.2 Modificar JSON Dinâmico

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Cria um objeto JSON programaticamente
    var root = std.json.ObjectMap.init(allocator);
    defer root.deinit();

    // Adiciona campos
    try root.put("name", std.json.Value{ .string = "Meu App" });
    try root.put("version", std.json.Value{ .string = "1.0.0" });
    try root.put("count", std.json.Value{ .integer = 42 });

    // Cria array
    var tags = std.json.Array.init(allocator);
    try tags.append(std.json.Value{ .string = "zig" });
    try tags.append(std.json.Value{ .string = "tutorial" });
    try root.put("tags", std.json.Value{ .array = tags });

    // Cria objeto aninhado
    var config = std.json.ObjectMap.init(allocator);
    try config.put("debug", std.json.Value{ .bool = true });
    try config.put("port", std.json.Value{ .integer = 8080 });
    try root.put("config", std.json.Value{ .object = config });

    // Serializa
    const value = std.json.Value{ .object = root };
    const json_str = try std.json.stringifyAlloc(allocator, value, .{ .whitespace = .indent_2 });
    defer allocator.free(json_str);

    std.debug.print("{s}\n", .{json_str});
}
```

## Parte 4: Exemplo Real — Cliente de API

Vamos criar um cliente completo para uma API REST:

```zig
// src/api_client.zig
const std = @import("std");
const http = std.http;

// Tipos da API
pub const Post = struct {
    userId: u32,
    id: u32,
    title: []const u8,
    body: []const u8,
};

pub const CreatePostRequest = struct {
    userId: u32,
    title: []const u8,
    body: []const u8,
};

pub const ApiClient = struct {
    allocator: std.mem.Allocator,
    base_url: []const u8,
    client: http.Client,

    pub fn init(allocator: std.mem.Allocator, base_url: []const u8) ApiClient {
        return .{
            .allocator = allocator,
            .base_url = base_url,
            .client = http.Client{ .allocator = allocator },
        };
    }

    pub fn deinit(self: *ApiClient) void {
        self.client.deinit();
    }

    /// GET /posts/{id}
    pub fn getPost(self: *ApiClient, id: u32) !Post {
        const url = try std.fmt.allocPrint(
            self.allocator,
            "{s}/posts/{d}",
            .{ self.base_url, id },
        );
        defer self.allocator.free(url);

        const response = try self.makeRequest(.GET, url, null);
        defer self.allocator.free(response);

        const parsed = try std.json.parseFromSlice(
            Post,
            self.allocator,
            response,
            .{},
        );
        defer parsed.deinit();

        // Copia os dados para retornar (strings são alocadas)
        return Post{
            .userId = parsed.value.userId,
            .id = parsed.value.id,
            .title = try self.allocator.dupe(u8, parsed.value.title),
            .body = try self.allocator.dupe(u8, parsed.value.body),
        };
    }

    /// POST /posts
    pub fn createPost(self: *ApiClient, request: CreatePostRequest) !Post {
        const url = try std.fmt.allocPrint(
            self.allocator,
            "{s}/posts",
            .{self.base_url},
        );
        defer self.allocator.free(url);

        // Serializa request
        const body = try std.json.stringifyAlloc(self.allocator, request, .{});
        defer self.allocator.free(body);

        const response = try self.makeRequest(.POST, url, body);
        defer self.allocator.free(response);

        const parsed = try std.json.parseFromSlice(
            Post,
            self.allocator,
            response,
            .{},
        );
        defer parsed.deinit();

        return Post{
            .userId = parsed.value.userId,
            .id = parsed.value.id,
            .title = try self.allocator.dupe(u8, parsed.value.title),
            .body = try self.allocator.dupe(u8, parsed.value.body),
        };
    }

    fn makeRequest(
        self: *ApiClient,
        method: http.Method,
        url: []const u8,
        body: ?[]const u8,
    ) ![]const u8 {
        const uri = try std.Uri.parse(url);

        var server_header_buffer: [4096]u8 = undefined;
        var request = try self.client.open(
            method,
            uri,
            .{
                .server_header_buffer = &server_header_buffer,
                .headers = .{
                    .content_type = if (body != null) .{ .override = "application/json" } else null,
                },
            },
        );
        defer request.deinit();

        // Escreve body se presente
        if (body) |b| {
            request.transfer_encoding = .{ .content_length = b.len };
            try request.send();
            try request.writeAll(b);
        } else {
            request.transfer_encoding = .chunked;
            try request.send();
        }

        try request.finish();
        try request.wait();

        // Lê resposta
        const response_body = try request.reader().readAllAlloc(
            self.allocator,
            1024 * 1024,
        );

        return response_body;
    }
};
```

### Usando o Cliente

```zig
// src/main.zig
const std = @import("std");
const ApiClient = @import("api_client.zig").ApiClient;
const CreatePostRequest = @import("api_client.zig").CreatePostRequest;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Inicializa cliente (usando JSONPlaceholder para testes)
    var client = ApiClient.init(allocator, "https://jsonplaceholder.typicode.com");
    defer client.deinit();

    std.debug.print("=== Testando API ===\n\n", .{});

    // GET post por ID
    std.debug.print("📥 Buscando post #1...\n", .{});
    const post = try client.getPost(1);
    defer {
        allocator.free(post.title);
        allocator.free(post.body);
    }

    std.debug.print("✅ Post encontrado:\n", .{});
    std.debug.print("   Título: {s}\n", .{post.title});
    std.debug.print("   User ID: {d}\n\n", .{post.userId});

    // POST cria novo post
    std.debug.print("📤 Criando novo post...\n", .{});
    const new_post = try client.createPost(.{
        .userId = 1,
        .title = "Meu Post em Zig",
        .body = "Este post foi criado usando Zig e JSON!",
    });
    defer {
        allocator.free(new_post.title);
        allocator.free(new_post.body);
    }

    std.debug.print("✅ Post criado com ID: {d}\n", .{new_post.id});
    std.debug.print("   Título: {s}\n", .{new_post.title});
}
```

### build.zig para o Cliente

```zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "api-client",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());

    const run_step = b.step("run", "Run API client");
    run_step.dependOn(&run_cmd.step);
}
```

## Parte 5: Tratamento de Erros

### 5.1 Erros Comuns de Parsing

```zig
const std = @import("std");

const User = struct {
    id: u32,
    name: []const u8,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON inválido
    const invalid_json =
        \\{
        \\  "id": "not_a_number",
        \\  "name": "João"
        \\}
    ;

    // Tenta parsear e trata erro
    const result = std.json.parseFromSlice(
        User,
        allocator,
        invalid_json,
        .{},
    );

    if (result) |parsed| {
        defer parsed.deinit();
        std.debug.print("✅ Sucesso: {s}\n", .{parsed.value.name});
    } else |err| {
        std.debug.print("❌ Erro ao parsear JSON: {}\n", .{err});
        // Erro esperado: error.InvalidCharacter (id deveria ser número)
    }
}
```

### 5.2 Validação de Dados

```zig
const std = @import("std");

const CreateUserRequest = struct {
    email: []const u8,
    age: u32,

    pub fn validate(self: CreateUserRequest) !void {
        // Valida email
        if (std.mem.indexOf(u8, self.email, "@") == null) {
            return error.InvalidEmail;
        }

        // Valida idade
        if (self.age < 13 or self.age > 120) {
            return error.InvalidAge;
        }
    }
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const json_str =
        \\{
        \\  "email": "joao@exemplo.com",
        \\  "age": 25
        \\}
    ;

    const parsed = try std.json.parseFromSlice(
        CreateUserRequest,
        allocator,
        json_str,
        .{},
    );
    defer parsed.deinit();

    // Valida após parse
    parsed.value.validate() catch |err| {
        std.debug.print("❌ Validação falhou: {}\n", .{err});
        return;
    };

    std.debug.print("✅ Dados válidos!\n", .{});
}
```

### 5.3 Estratégia de Fallback

```zig
const std = @import("std");

// Struct flexível que aceita variações
const ApiResponse = struct {
    status: []const u8,
    data: ?std.json.Value,        // Opcional
    error: ?[]const u8,           // Opcional
    message: ?[]const u8,         // Opcional (fallback)
};

pub fn handleApiResponse(allocator: std.mem.Allocator, json_str: []const u8) !void {
    const parsed = try std.json.parseFromSlice(
        ApiResponse,
        allocator,
        json_str,
        .{},
    );
    defer parsed.deinit();

    const response = parsed.value;

    if (std.mem.eql(u8, response.status, "error")) {
        // Tenta várias fontes de mensagem de erro
        const error_msg = response.error orelse
            (if (response.message) |m| m else "Erro desconhecido");
        std.debug.print("❌ Erro: {s}\n", .{error_msg});
        return;
    }

    std.debug.print("✅ Sucesso!\n", .{});

    if (response.data) |data| {
        // Processa dados
        std.debug.print("Dados recebidos: {}\n", .{data});
    }
}
```

## Parte 6: Casos Avançados

### 6.1 JSON com Unions (Tipos Variados)

```zig
const std = @import("std");

// Union para representar valor que pode ser string ou número
const StringOrNumber = union(enum) {
    string: []const u8,
    number: f64,
};

const FlexibleValue = struct {
    id: u32,
    value: StringOrNumber,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON onde "value" pode ser string ou número
    const json_str =
        \\[
        \\  {"id": 1, "value": "texto"},
        \\  {"id": 2, "value": 42.5}
        \\]
    ;

    const parsed = try std.json.parseFromSlice(
        []const FlexibleValue,
        allocator,
        json_str,
        .{},
    );
    defer parsed.deinit();

    for (parsed.value) |item| {
        std.debug.print("ID: {d}, Value: ", .{item.id});
        switch (item.value) {
            .string => |s| std.debug.print("(string) {s}\n", .{s}),
            .number => |n| std.debug.print("(number) {d}\n", .{n}),
        }
    }
}
```

### 6.2 Parse Parcial de JSON

```zig
const std = @import("std");

// Parse apenas os campos que interessam
const PartialUser = struct {
    id: u32,
    name: []const u8,
    // Ignora: email, phone, website, company, address...
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON grande com muitos campos
    const large_json =
        \\{
        \\  "id": 1,
        \\  "name": "João Silva",
        \\  "username": "joaosilva",
        \\  "email": "joao@exemplo.com",
        \\  "address": {
        \\    "street": "Rua Principal",
        \\    "city": "São Paulo"
        \\  },
        \\  "phone": "11-99999-9999",
        \\  "website": "joao.dev",
        \\  "company": {
        \\    "name": "Tech Corp",
        \\    "catchPhrase": "Inovação sempre"
        \\  }
        \\}
    ;

    // Parse só id e name — outros campos são ignorados
    const parsed = try std.json.parseFromSlice(
        PartialUser,
        allocator,
        large_json,
        .{},
    );
    defer parsed.deinit();

    std.debug.print("ID: {d}, Nome: {s}\n", .{
        parsed.value.id,
        parsed.value.name,
    });
}
```

### 6.3 Ignorar Campos Desconhecidos

```zig
const std = @import("std");

const Config = struct {
    name: []const u8,
    version: []const u8,

    // Ignora campos extras no JSON
    pub const __json_options = .{
        .ignore_unknown_fields = true,
    };
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // JSON com campos extras que serão ignorados
    const json_str =
        \\{
        \\  "name": "meu-app",
        \\  "version": "1.0.0",
        \\  "unknown_field_1": "valor",
        \\  "unknown_field_2": 123,
        \\  "future_feature": true
        \\}
    ;

    const parsed = try std.json.parseFromSlice(
        Config,
        allocator,
        json_str,
        .{ .ignore_unknown_fields = true },
    );
    defer parsed.deinit();

    std.debug.print("✅ Parse bem-sucedido ignorando campos extras\n", .{});
    std.debug.print("Name: {s}, Version: {s}\n", .{
        parsed.value.name,
        parsed.value.version,
    });
}
```

## Resumo e Checklist

Você aprendeu a trabalhar com JSON em Zig:

✅ **Parse básico** — Structs ↔ JSON  
✅ **Arrays e campos opcionais** — `[]T` e `?T`  
✅ **Serialização** — Struct → JSON formatado  
✅ **JSON dinâmico** — `std.json.Value` para estruturas desconhecidas  
✅ **Cliente de API** — Requisições HTTP com JSON  
✅ **Tratamento de erros** — Validação e fallback  
✅ **Casos avançados** — Unions, parse parcial, campos ignorados

### Tabela Rápida de Referência

| Operação | Função | Exemplo |
|----------|--------|---------|
| Parse para struct | `parseFromSlice(T, allocator, json, .{})` | `const user = parsed.value;` |
| Serializar struct | `stringifyAlloc(allocator, value, .{})` | `const json = try std.json.stringifyAlloc(...);` |
| JSON dinâmico | `parseFromSlice(std.json.Value, ...)` | `root.object.get("key").?.string` |
| Pretty print | `.{ .whitespace = .indent_2 }` | JSON com indentação |
| Campo opcional | `?T` na struct | `bio: ?[]const u8` |
| Ignorar campos | `.ignore_unknown_fields = true` | Usar em parseOptions |

### Próximos Passos

Aprofunde seus conhecimentos:

- 🌐 [Como Criar um Servidor HTTP em Zig](/tutoriais/zig-http-server/) — Crie APIs REST que usam JSON
- 🛠️ [Como Criar uma CLI em Zig](/tutoriais/cli-em-zig/) — Ferramentas de linha de comando com configuração JSON
- 🧪 [Testes em Zig: Guia Completo](/tutoriais/testes-zig/) — Teste seu parsing de JSON
- 📦 [Tratamento de Erros em Zig](/tutoriais/tratamento-de-erros-em-zig/) — Error handling avançado

### Exercícios Práticos

1. **Parse de API pública**: Escreva um programa que consome a API do GitHub e lista repositórios de um usuário
2. **Configuração JSON**: Crie um sistema de configuração que lê e escreve settings.json
3. **Validador de JSON**: Implemente um programa que valida se um arquivo JSON está bem formado
4. **Conversor CSV→JSON**: Converta arquivos CSV para formato JSON

O parsing de JSON em Zig é manual e explícito, sem reflection de runtime. Para comparar abordagens, <a href="https://golang.com.br/artigos/go-json/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go usa encoding/json com struct tags para serialização automática</a>, enquanto <a href="https://python.dev.br/artigos/python-json/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">Python conta com o módulo json integrado na biblioteca padrão</a>.

### Recursos Adicionais

- [Documentação std.json](https://ziglang.org/documentation/master/std/#std.json)
- [Ziglearn - Chapter 5](https://ziglearn.org/chapter-5/)
- [JSONPlaceholder](https://jsonplaceholder.typicode.com/) — API gratuita para testes

---

**Gostou deste tutorial?** Compartilhe com a comunidade Zig! Tem dúvidas ou sugestões? Entre em contato conosco.

*Última atualização: 10 de fevereiro de 2026*  
*Versão do Zig: 0.13.0*
