std.http.Client — Cliente HTTP
O std.http.Client permite fazer requisições HTTP/1.1 a servidores remotos. Ele suporta todos os métodos HTTP, cabeçalhos customizados, envio de corpo (payload), redirecionamentos automáticos e TLS para conexões HTTPS. É a ferramenta padrão para consumir APIs REST, baixar arquivos e comunicar com serviços web.
Visão Geral
const std = @import("std");
const http = std.http;
const Client = http.Client;
Criação e Destruição
// O Client é uma struct que requer apenas um allocator
var client = http.Client{ .allocator = allocator };
defer client.deinit();
Funções Principais
fetch
A principal função para fazer requisições:
pub fn fetch(self: *Client, options: FetchOptions) !FetchResult
FetchOptions
pub const FetchOptions = struct {
// URL ou URI pré-parseado
location: Location,
// Método HTTP (padrão: GET)
method: http.Method = .GET,
// Cabeçalhos extras
headers: Headers = .{},
extra_headers: []const http.Header = &.{},
// Corpo da requisição (para POST, PUT, etc.)
payload: ?[]const u8 = null,
// Onde armazenar a resposta
response_storage: ResponseStorage,
// Seguir redirecionamentos
max_redirects: u32 = 3,
// ...
};
FetchResult
pub const FetchResult = struct {
status: http.Status,
// ...
};
Exemplo 1: Consumindo API REST com GET
const std = @import("std");
const Post = struct {
userId: u32,
id: u32,
title: []const u8,
body: []const u8,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();
var body = std.ArrayList(u8).init(allocator);
defer body.deinit();
// GET para API pública
const result = try client.fetch(.{
.location = .{ .url = "https://jsonplaceholder.typicode.com/posts/1" },
.response_storage = .{ .dynamic = &body },
});
const stdout = std.io.getStdOut().writer();
try stdout.print("Status: {d}\n", .{@intFromEnum(result.status)});
if (result.status == .ok) {
// Desserializa o JSON
const parsed = try std.json.parseFromSlice(
Post,
allocator,
body.items,
.{ .ignore_unknown_fields = true },
);
defer parsed.deinit();
const post = parsed.value;
try stdout.print("Título: {s}\n", .{post.title});
try stdout.print("Autor (userId): {d}\n", .{post.userId});
}
}
Exemplo 2: POST com Payload JSON
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();
// Prepara o payload JSON
const dados = .{
.title = "Novo Post",
.body = "Conteúdo do post criado via Zig",
.userId = @as(u32, 1),
};
const payload = try std.json.stringifyAlloc(allocator, dados, .{});
defer allocator.free(payload);
var body = std.ArrayList(u8).init(allocator);
defer body.deinit();
// Faz a requisição POST
const result = try client.fetch(.{
.location = .{ .url = "https://jsonplaceholder.typicode.com/posts" },
.method = .POST,
.headers = .{
.content_type = .{ .override = "application/json" },
},
.payload = payload,
.response_storage = .{ .dynamic = &body },
});
const stdout = std.io.getStdOut().writer();
try stdout.print("Status: {d} ({s})\n", .{
@intFromEnum(result.status),
result.status.phrase() orelse "?",
});
try stdout.print("Resposta:\n{s}\n", .{body.items});
}
Exemplo 3: Download de Arquivo
const std = @import("std");
fn downloadFile(
allocator: std.mem.Allocator,
url: []const u8,
caminho_destino: []const u8,
) !usize {
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();
var body = std.ArrayList(u8).init(allocator);
defer body.deinit();
const result = try client.fetch(.{
.location = .{ .url = url },
.response_storage = .{ .dynamic = &body },
});
if (result.status != .ok) {
return error.HttpError;
}
// Salva em arquivo
const arquivo = try std.fs.cwd().createFile(caminho_destino, .{});
defer arquivo.close();
try arquivo.writeAll(body.items);
return body.items.len;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
const url = "https://example.com/";
const destino = "/tmp/exemplo.html";
try stdout.print("Baixando {s}...\n", .{url});
if (downloadFile(allocator, url, destino)) |bytes| {
try stdout.print("Download completo: {d} bytes salvos em {s}\n", .{
bytes, destino,
});
} else |err| {
try stdout.print("Erro no download: {}\n", .{err});
}
}
Padrões Comuns
Cabeçalhos de Autenticação
const result = try client.fetch(.{
.location = .{ .url = url },
.extra_headers = &.{
.{ .name = "Authorization", .value = "Bearer meu_token_aqui" },
.{ .name = "Accept", .value = "application/json" },
},
.response_storage = .{ .dynamic = &body },
});
Tratamento de Erros HTTP
const result = try client.fetch(.{ ... });
switch (result.status) {
.ok, .created => { /* sucesso */ },
.unauthorized => { /* re-autenticar */ },
.not_found => { /* recurso não existe */ },
else => { /* erro genérico */ },
}
Módulos Relacionados
- std.http — Visão geral do módulo HTTP
- std.http.Server — Servidor HTTP
- std.json — Serialização/desserialização JSON
- std.Uri — Parsing de URLs
- std.net — Networking de baixo nível