std.http em Zig — Referência e Exemplos

std.http — HTTP Client e Server

O módulo std.http fornece uma implementação completa de HTTP/1.1 na biblioteca padrão do Zig, incluindo tanto um cliente para fazer requisições quanto um servidor para recebê-las. Ele é construído sobre std.net e usa as interfaces de I/O do Zig, oferecendo suporte a chunked transfer encoding, cabeçalhos, redirecionamentos e TLS.

Visão Geral

const std = @import("std");
const http = std.http;

O módulo é dividido em:

  • http.Client — Para fazer requisições HTTP
  • http.Server — Para servir requisições HTTP
  • http.Method — Enum com métodos HTTP
  • http.Status — Enum com códigos de status
  • http.Header — Tipo para cabeçalhos

Tipos Principais

http.Method

pub const Method = enum {
    GET,
    HEAD,
    POST,
    PUT,
    DELETE,
    CONNECT,
    OPTIONS,
    TRACE,
    PATCH,
    // ...
};

http.Status

pub const Status = enum(u10) {
    ok = 200,
    created = 201,
    no_content = 204,
    moved_permanently = 301,
    found = 302,
    bad_request = 400,
    unauthorized = 401,
    forbidden = 403,
    not_found = 404,
    internal_server_error = 500,
    // ...

    pub fn phrase(self: Status) ?[]const u8
};

Funções Principais

Cliente

// Cria um cliente HTTP
pub fn Client.init(allocator: Allocator) Client

// Faz uma requisição
pub fn Client.fetch(self: *Client, options: FetchOptions) !FetchResult

// Libera recursos
pub fn Client.deinit(self: *Client) void

Servidor

// Cria servidor HTTP escutando em endereço
pub fn Server.init(config: Config) Server

// Aceita próxima requisição
pub fn Server.accept(self: *Server) !Request

// Para o servidor
pub fn Server.deinit(self: *Server) void

Exemplo 1: Requisição GET com Cliente HTTP

const std = @import("std");

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

    // Cria o cliente
    var client = std.http.Client{ .allocator = allocator };
    defer client.deinit();

    // Buffer para o corpo da resposta
    var body = std.ArrayList(u8).init(allocator);
    defer body.deinit();

    // Faz a requisição GET
    const result = try client.fetch(.{
        .location = .{ .url = "http://example.com/" },
        .response_storage = .{ .dynamic = &body },
    });

    const stdout = std.io.getStdOut().writer();
    try stdout.print("Status: {d} {s}\n", .{
        @intFromEnum(result.status),
        result.status.phrase() orelse "Desconhecido",
    });
    try stdout.print("Tamanho do corpo: {d} bytes\n", .{body.items.len});

    // Mostra os primeiros 200 caracteres
    const preview_len = @min(body.items.len, 200);
    try stdout.print("Preview:\n{s}...\n", .{body.items[0..preview_len]});
}

Exemplo 2: Requisição POST com 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();

    const payload =
        \\{"nome": "João", "email": "joao@exemplo.com"}
    ;

    var body = std.ArrayList(u8).init(allocator);
    defer body.deinit();

    const result = try client.fetch(.{
        .location = .{ .url = "https://httpbin.org/post" },
        .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}\n", .{@intFromEnum(result.status)});
    try stdout.print("Resposta: {s}\n", .{body.items});
}

Exemplo 3: Servidor HTTP Simples

const std = @import("std");
const http = std.http;
const net = std.net;

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

    const addr = try net.Address.parseIp4("127.0.0.1", 8080);
    var server = try addr.listen(.{ .reuse_address = true });
    defer server.deinit();

    std.debug.print("Servidor HTTP em http://127.0.0.1:8080\n", .{});

    while (true) {
        var connection = try server.accept();

        var buf: [4096]u8 = undefined;
        var http_server = http.Server.init(connection, &buf);

        var request = http_server.receiveHead() catch continue;

        // Constrói resposta
        const corpo = "Olá do servidor Zig!";
        request.respond(corpo, .{
            .extra_headers = &.{
                .{ .name = "content-type", .value = "text/plain; charset=utf-8" },
            },
        }) catch continue;

        std.debug.print("Requisição: {s} {s}\n", .{
            @tagName(request.head.method),
            request.head.target,
        });
    }
}

Códigos de Status Comuns

CódigoConstanteSignificado
200.okSucesso
201.createdRecurso criado
301.moved_permanentlyRedirecionamento permanente
400.bad_requestRequisição inválida
401.unauthorizedNão autenticado
404.not_foundNão encontrado
500.internal_server_errorErro interno

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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