O Zig é uma linguagem de sistemas sem garbage collector que oferece controle manual de memória, excelente interoperabilidade com C e compilação para binários enxutos — características ideais para aplicações de alta performance que precisam validar CPF com latência previsível. Para consumir a API da CPFHub.io em Zig, use std.http.Client com um GET https://api.cpfhub.io/cpf/{CPF} autenticado pelo header x-api-key; a resposta chega em ~900ms e traz nome, data de nascimento e status do documento. Consulte a documentação oficial do Zig para instalar o toolchain antes de começar.
1. Pré-requisitos
-
Zig 0.13+ instalado.
-
Uma conta gratuita na CPFHub.io
2. Estrutura do projeto
Crie a estrutura básica do projeto Zig:
cpf-validator-zig/
├── build.zig
├── build.zig.zon
└── src/
├── main.zig
├── cpfhub.zig
└── json_parser.zig
3. Configure o build.zig
// build.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 = "cpf-validator",
.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 the application");
run_step.dependOn(&run_cmd.step);
}
4. Implemente o cliente HTTP
Crie o módulo de consulta de CPF usando std.http.Client:
// src/cpfhub.zig
const std = @import("std");
const http = std.http;
const mem = std.mem;
const json = std.json;
pub const CpfData = struct {
cpf: []const u8 = "",
name: []const u8 = "",
nameUpper: []const u8 = "",
gender: []const u8 = "",
birthDate: []const u8 = "",
day: u32 = 0,
month: u32 = 0,
year: u32 = 0,
};
pub const CpfError = error{
InvalidCpf,
NotFound,
Unauthorized,
RateLimited,
Timeout,
ConnectionError,
ParseError,
ApiError,
};
pub const Config = struct {
api_key: []const u8,
base_url: []const u8 = "https://api.cpfhub.io",
timeout_ns: u64 = 5 * std.time.ns_per_s,
};
/// Remove caracteres não numéricos do CPF.
pub fn limparCpf(cpf: []const u8, buf: []u8) ![]u8 {
var len: usize = 0;
for (cpf) |c| {
if (c >= '0' and c <= '9') {
if (len >= buf.len) return error.BufferTooSmall;
buf[len] = c;
len += 1;
}
}
return buf[0..len];
}
/// Consulta dados de um CPF na API da CPFHub.io.
pub fn consultarCpf(
allocator: mem.Allocator,
config: Config,
cpf: []const u8,
) !CpfData {
// Limpar CPF
var cpf_buf: [11]u8 = undefined;
const cpf_limpo = limparCpf(cpf, &cpf_buf) catch {
return CpfError.InvalidCpf;
};
if (cpf_limpo.len != 11) {
return CpfError.InvalidCpf;
}
// Construir URL
var url_buf: [256]u8 = undefined;
const url = std.fmt.bufPrint(&url_buf, "{s}/cpf/{s}", .{
config.base_url,
cpf_limpo,
}) catch {
return CpfError.ApiError;
};
// Criar cliente HTTP
var client = http.Client{ .allocator = allocator };
defer client.deinit();
// Configurar URI
const uri = std.Uri.parse(url) catch {
return CpfError.ApiError;
};
// Headers
const headers = http.Header{
.name = "x-api-key",
.value = config.api_key,
};
const accept_header = http.Header{
.name = "Accept",
.value = "application/json",
};
var extra_headers = [_]http.Header{ headers, accept_header };
// Fazer requisição
var req = client.open(.GET, uri, .{
.extra_headers = &extra_headers,
.keep_alive = false,
}) catch {
return CpfError.ConnectionError;
};
defer req.deinit();
req.send() catch {
return CpfError.ConnectionError;
};
req.wait() catch {
return CpfError.Timeout;
};
// Verificar status
// Nota: a CPFHub.io não retorna 429 ao atingir o limite — cobra R$0,15/consulta adicional.
const status = req.response.status;
switch (status) {
.ok => {},
.bad_request => return CpfError.InvalidCpf,
.unauthorized => return CpfError.Unauthorized,
.not_found => return CpfError.NotFound,
else => return CpfError.ApiError,
}
// Ler body
var body_buf: [4096]u8 = undefined;
const body_len = req.reader().readAll(&body_buf) catch {
return CpfError.ParseError;
};
const body = body_buf[0..body_len];
// Parsear JSON
const parsed = json.parseFromSlice(
struct {
success: bool,
data: CpfData,
},
allocator,
body,
.{},
) catch {
return CpfError.ParseError;
};
defer parsed.deinit();
if (!parsed.value.success) {
return CpfError.ApiError;
}
return parsed.value.data;
}
5. Implemente o ponto de entrada
// src/main.zig
const std = @import("std");
const cpfhub = @import("cpfhub.zig");
pub fn main() !void {
const allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer();
const config = cpfhub.Config{
.api_key = "SUA_CHAVE_DE_API",
.base_url = "https://api.cpfhub.io",
.timeout_ns = 5 * std.time.ns_per_s,
};
const cpf = "12345678900";
try stdout.print("Consultando CPF: {s}\n", .{cpf});
const resultado = cpfhub.consultarCpf(allocator, config, cpf) catch |err| {
const msg = switch (err) {
cpfhub.CpfError.InvalidCpf => "CPF invalido",
cpfhub.CpfError.NotFound => "CPF nao encontrado",
cpfhub.CpfError.Unauthorized => "Chave de API invalida",
cpfhub.CpfError.RateLimited => "Rate limit excedido",
cpfhub.CpfError.Timeout => "Timeout na consulta",
cpfhub.CpfError.ConnectionError => "Erro de conexao",
cpfhub.CpfError.ParseError => "Erro ao processar resposta",
cpfhub.CpfError.ApiError => "Erro da API",
else => "Erro desconhecido",
};
try stdout.print("Erro: {s}\n", .{msg});
return;
};
try stdout.print("\n--- Resultado ---\n", .{});
try stdout.print("Nome: {s}\n", .{resultado.name});
try stdout.print("CPF: {s}\n", .{resultado.cpf});
try stdout.print("Genero: {s}\n", .{resultado.gender});
try stdout.print("Nascimento: {s}\n", .{resultado.birthDate});
}
6. Compile e execute
zig build run
Saída esperada:
Consultando CPF: 12345678900
--- Resultado ---
Nome: João da Silva
CPF: 12345678900
Genero: M
Nascimento: 15/06/1990
7. Versão com servidor HTTP
Para expor a consulta como endpoint HTTP usando std.http.Server:
// src/server.zig
const std = @import("std");
const cpfhub = @import("cpfhub.zig");
pub fn main() !void {
const allocator = std.heap.page_allocator;
var server = std.http.Server.init(allocator, .{
.reuse_address = true,
});
defer server.deinit();
const address = std.net.Address.parseIp("0.0.0.0", 8080) catch unreachable;
server.listen(address) catch |err| {
std.log.err("Erro ao iniciar servidor: {}", .{err});
return;
};
std.log.info("Servidor iniciado na porta 8080", .{});
while (true) {
var response = server.accept() catch continue;
defer response.deinit();
handleRequest(allocator, &response) catch |err| {
std.log.err("Erro ao processar requisição: {}", .{err});
};
}
}
fn handleRequest(
allocator: std.mem.Allocator,
response: *std.http.Server.Response,
) !void {
const config = cpfhub.Config{
.api_key = "SUA_CHAVE_DE_API",
};
// Extrair CPF da URL (esperado: /api/cpf/12345678900)
const path = response.request.target;
if (!std.mem.startsWith(u8, path, "/api/cpf/")) {
response.status = .not_found;
try response.do_send();
return;
}
const cpf = path[9..];
const resultado = cpfhub.consultarCpf(allocator, config, cpf) catch {
response.status = .internal_server_error;
try response.do_send();
return;
};
// Construir resposta JSON
var buf: [1024]u8 = undefined;
const json_response = std.fmt.bufPrint(&buf,
\\{{"success":true,"data":{{"cpf":"{s}","name":"{s}","gender":"{s}","birthDate":"{s}"}}}}
, .{
resultado.cpf,
resultado.name,
resultado.gender,
resultado.birthDate,
}) catch {
response.status = .internal_server_error;
try response.do_send();
return;
};
response.status = .ok;
response.transfer_encoding = .{ .content_length = json_response.len };
try response.do_send();
_ = try response.write(json_response);
try response.finish();
}
8. Benchmarks de performance
O Zig permite executar benchmarks simples para medir a latência da integração:
// src/benchmark.zig
const std = @import("std");
const cpfhub = @import("cpfhub.zig");
pub fn main() !void {
const allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer();
const config = cpfhub.Config{
.api_key = "SUA_CHAVE_DE_API",
};
const iterations = 10;
var total_ns: u64 = 0;
for (0..iterations) |i| {
const start = std.time.nanoTimestamp();
_ = cpfhub.consultarCpf(allocator, config, "12345678900") catch {};
const elapsed = @as(u64, @intCast(std.time.nanoTimestamp() - start));
total_ns += elapsed;
try stdout.print("Iteração {d}: {d}ms\n", .{
i + 1,
elapsed / std.time.ns_per_ms,
});
}
try stdout.print("\nMédia: {d}ms\n", .{
total_ns / iterations / std.time.ns_per_ms,
});
}
Espere latências em torno de ~900ms por consulta, tempo que reflete o processamento da API — o overhead do cliente Zig é desprezível.
9. Boas práticas
-
Alocação -- Use alocadores explícitos para controle total de memória. Prefira
page_allocatorpara simplicidade ouArenaAllocatorpara performance. -
Buffers fixos -- Use buffers de tamanho fixo na stack para dados previsíveis, evitando alocações no heap.
-
Erros -- Use o sistema de erros do Zig (error unions) para tratamento explícito e sem overhead de exceções.
-
Timeout -- Configure timeout na requisição HTTP para evitar bloqueios indefinidos, respeitando a latência de ~900ms da API.
-
Compilação -- Use
zig build -Doptimize=ReleaseFastpara máxima performance em produção. -
LGPD -- A API da CPFHub.io é 100% compatível com a LGPD. Em aplicações de alta performance, garanta que logs e buffers contendo dados pessoais sejam limpos adequadamente.
Perguntas frequentes
Por que usar Zig para consumir uma API de CPF em vez de linguagens como Go ou Rust?
Zig oferece controle total sobre alocações de memória e zero overhead de runtime, o que o torna adequado quando o serviço de consulta de CPF precisa coexistir com código C legado ou operar em ambientes com memória restrita. Para a maioria dos projetos web, Go ou Rust entregam produtividade maior; Zig brilha em integrações de baixo nível com código C ou em ferramentas de sistema onde cada byte importa.
Como configurar o timeout da requisição HTTP em Zig para respeitar a latência da API?
A API da CPFHub.io responde em ~900ms. No cliente Zig com std.http.Client, configure timeout_ns com pelo menos 5 segundos (5 * std.time.ns_per_s) para absorver variações de rede sem falsos timeouts. Ajuste conforme o SLA do seu serviço — ambientes com latência de rede alta podem precisar de 8 a 10 segundos.
O que acontece se o limite do plano gratuito for ultrapassado durante os benchmarks?
A CPFHub.io não bloqueia requisições ao atingir o limite do plano gratuito (50 consultas/mês). Cada consulta adicional é cobrada a R$0,15 automaticamente. Ao rodar benchmarks com múltiplas iterações, monitore o consumo no painel para evitar cobranças não planejadas — ou use o plano Pro com 1.000 consultas por R$149/mês.
Como garantir que buffers Zig com dados de CPF sejam limpos após o uso?
Use @memset para zerar explicitamente qualquer buffer que tenha armazenado CPF ou dados pessoais antes de liberá-lo ou reutilizá-lo. O Zig não inicializa memória automaticamente, o que exige disciplina do desenvolvedor — mas também garante que nenhum dado sensível vaze entre requisições em buffers reutilizados.
Conclusão
Consumir a API da CPFHub.io
Cadastre-se em cpfhub.io
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



