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

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ísticastd.json ZigOutras Linguagens
Zero allocations✅ Possível⚠️ Raro
Type safety✅ Compile-time⚠️ Runtime
Performance✅ NativaVariá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
  2. Conhecimento básico de Zig — structs, allocators, error handling
  3. Familiaridade com JSON — objetos, arrays, tipos de dados

Setup do Projeto

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:

// 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:

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:

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:

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):

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:

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:

{"id":1,"title":"Implementar parsing JSON","completed":false,"priority":"high"}

2.2 Pretty Print (JSON Formatado)

Para output legível, use .whitespace:

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:

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

2.3 Escrever JSON em Arquivo

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

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

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:

// 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

// 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

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

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

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

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)

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

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

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âmicostd.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çãoFunçãoExemplo
Parse para structparseFromSlice(T, allocator, json, .{})const user = parsed.value;
Serializar structstringifyAlloc(allocator, value, .{})const json = try std.json.stringifyAlloc(...);
JSON dinâmicoparseFromSlice(std.json.Value, ...)root.object.get("key").?.string
Pretty print.{ .whitespace = .indent_2 }JSON com indentação
Campo opcional?T na structbio: ?[]const u8
Ignorar campos.ignore_unknown_fields = trueUsar em parseOptions

Próximos Passos

Aprofunde seus conhecimentos:

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

Recursos Adicionais


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

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.