Se um exemplo com try req.headers.append("Nome", "valor") parou de compilar, a correção mais comum nas versões recentes do Zig é não alterar os headers depois de criar a requisição. Passe os cabeçalhos como uma lista de std.http.Header em extra_headers, normalmente usando std.http.Client.fetch. A API HTTP da biblioteca padrão mudou várias vezes antes do Zig 1.0, por isso muitos snippets antigos encontrados em fóruns e repositórios já não correspondem ao release instalado.
A substituição direta costuma ser esta:
// Exemplo antigo encontrado na internet:
try req.headers.append("User-Agent", "minha-app/1.0");
try req.headers.append("Accept", "application/json");
// Padrão atual com fetch:
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/dados" },
.extra_headers = &.{
.{ .name = "User-Agent", .value = "minha-app/1.0" },
.{ .name = "Accept", .value = "application/json" },
},
.response_storage = .{ .dynamic = &body },
});
Este guia explica por que o erro acontece, como migrar GET, POST, Bearer token e API key, e quais detalhes verificar quando o código ainda falha.
Resposta rápida
| Código ou objetivo | Caminho recomendado |
|---|---|
req.headers.append(...) não existe | Passe extra_headers = &.{ ... } nas opções da operação HTTP |
| GET simples | Use client.fetch com location, extra_headers e response_storage |
| POST JSON | Use method = .POST, payload e o header tipado de content_type |
| Bearer token dinâmico | Monte o valor em um buffer que continue válido durante a chamada |
| Header conhecido da stdlib | Prefira o campo tipado em headers quando ele existir |
| Header customizado | Use extra_headers com pares .name e .value |
| Exemplo de outra versão | Confirme a versão com zig version e consulte a documentação correspondente |
Para uma visão completa do cliente, veja o tutorial de std.http.Client. Se você precisa apenas copiar uma requisição pronta, consulte as receitas de HTTP GET em Zig e HTTP POST em Zig.
Por que req.headers.append deixou de funcionar?
Zig ainda está antes da versão 1.0, então APIs da biblioteca padrão podem mudar entre releases. O módulo std.http passou por redesigns que alteraram a criação da requisição, os tipos de headers, a sequência de envio e as abstrações de I/O.
Um exemplo antigo pode falhar com mensagens parecidas com estas:
error: no field named 'headers' in struct 'http.Client.Request'
error: no field or member function named 'append'
error: expected type '[]const http.Header', found ...
Esses erros não significam necessariamente que headers customizados foram removidos. Em geral, significa que eles agora são fornecidos como configuração da operação, em vez de serem anexados por mutação depois que o objeto foi criado.
A primeira etapa do diagnóstico é sempre registrar o release real:
zig version
Depois, compare o código com a documentação desse release. Não misture um exemplo de Zig 0.12, outro de 0.14 e tipos de 0.16 no mesmo arquivo. Essa combinação é uma das causas mais frequentes de erros em std.http.
GET com headers usando extra_headers
O exemplo abaixo faz um GET, envia User-Agent e Accept, limita a memória disponível para a resposta e verifica o status HTTP.
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();
var body = std.ArrayList(u8).init(allocator);
defer body.deinit();
const result = try client.fetch(.{
.location = .{
.url = "https://api.github.com/repos/ziglang/zig",
},
.extra_headers = &.{
.{ .name = "User-Agent", .value = "zig-exemplo/1.0" },
.{ .name = "Accept", .value = "application/vnd.github+json" },
},
.response_storage = .{ .dynamic = &body },
});
if (result.status != .ok) {
std.log.err("API respondeu com status {d}", .{
@intFromEnum(result.status),
});
return error.HttpStatusInesperado;
}
std.debug.print("{s}\n", .{body.items});
}
extra_headers recebe uma slice de std.http.Header. A sintaxe &.{ ... } cria uma lista literal adequada para valores fixos. Para integrações reais, mantenha um limite operacional para a resposta; a forma exata desse limite depende da API de response_storage disponível no seu release e da estratégia usada pelo programa.
Header tipado ou extra_headers?
As opções de fetch normalmente separam headers conhecidos de headers arbitrários. Um Content-Type pode ter um campo tipado, enquanto X-API-Key, Idempotency-Key ou um header específico do fornecedor entra em extra_headers.
Exemplo de POST JSON:
const payload =
\\{"nome":"Ana","ativo":true}
;
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/usuarios" },
.method = .POST,
.headers = .{
.content_type = .{ .override = "application/json" },
},
.extra_headers = &.{
.{ .name = "Accept", .value = "application/json" },
.{ .name = "User-Agent", .value = "minha-api-client/1.0" },
},
.payload = payload,
.response_storage = .{ .dynamic = &body },
});
A regra prática é:
- use o campo tipado quando a versão instalada o oferecer;
- use
extra_headerspara extensões e valores sem campo próprio; - não envie duas versões conflitantes do mesmo header;
- confira se o nome e o valor continuam vivos durante a operação.
Authorization Bearer com valor dinâmico
Tokens normalmente chegam por variável de ambiente, arquivo seguro ou serviço de credenciais. Como o valor completo precisa incluir o prefixo Bearer , você pode montá-lo em um buffer local.
var authorization_buffer: [2048]u8 = undefined;
const authorization = try std.fmt.bufPrint(
&authorization_buffer,
"Bearer {s}",
.{token},
);
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/conta" },
.extra_headers = &.{
.{ .name = "Authorization", .value = authorization },
.{ .name = "Accept", .value = "application/json" },
},
.response_storage = .{ .dynamic = &body },
});
O buffer precisa permanecer válido até fetch terminar. Não devolva uma slice apontando para uma variável local que já saiu de escopo e não reutilize o mesmo buffer em operações concorrentes.
Também evite imprimir o header em logs. Em produção, registre que a autenticação foi configurada, mas nunca o token. O guia de configuração segura e segredos em Zig detalha esse cuidado.
API key e headers específicos
Para uma chave enviada em X-API-Key, a configuração é direta:
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/relatorio" },
.extra_headers = &.{
.{ .name = "X-API-Key", .value = api_key },
.{ .name = "Accept", .value = "application/json" },
},
.response_storage = .{ .dynamic = &body },
});
Antes de implementar, confirme como o fornecedor espera receber a credencial. Algumas APIs usam Authorization: Bearer, outras X-API-Key, e sistemas legados podem exigir nomes próprios. Não mova uma chave para a query string apenas para contornar um problema de header: URLs aparecem com mais facilidade em logs, histórico, métricas e traces.
Migração de um exemplo antigo passo a passo
Considere este padrão antigo:
var req = try client.request(.GET, uri, .{
.allocator = allocator,
}, .{});
defer req.deinit();
try req.headers.append("User-Agent", "app/1.0");
try req.headers.append("Accept", "application/json");
try req.start();
try req.finish();
try req.wait();
Para migrá-lo sem carregar partes incompatíveis da API antiga:
- mantenha a criação e o
deinitdostd.http.Client; - substitua a sequência manual por
client.fetchquando ela atender ao caso; - mova URL e método para as opções de
fetch; - converta cada
append(nome, valor)em umstd.http.Header; - defina onde o corpo da resposta será armazenado;
- valide
result.statusantes de fazer parse do body; - rode
zig fmte os testes do projeto.
O equivalente fica conceitualmente assim:
const result = try client.fetch(.{
.location = .{ .url = url },
.method = .GET,
.extra_headers = &.{
.{ .name = "User-Agent", .value = "app/1.0" },
.{ .name = "Accept", .value = "application/json" },
},
.response_storage = .{ .dynamic = &body },
});
Essa migração é melhor do que tentar encontrar um novo lugar para chamar append, pois evita misturar o ciclo de vida antigo da requisição com as opções atuais.
O que verificar se extra_headers também der erro
1. A versão do exemplo não é a sua
Confirme:
zig version
Se o projeto fixa uma versão em CI, container, mise, asdf ou zigup, use a mesma localmente. “Funciona na minha máquina” costuma significar apenas que duas versões diferentes estão compilando APIs diferentes.
2. O tipo esperado mudou
Leia a assinatura de FetchOptions na documentação ou no código da stdlib instalada. O compilador do Zig normalmente mostra o tipo esperado e a origem da declaração. Siga essa trilha em vez de aplicar casts aleatórios.
3. O valor do header não vive tempo suficiente
Um header guarda slices; ele não necessariamente copia todos os valores. Strings literais vivem pelo programa inteiro, mas valores formatados precisam permanecer válidos durante a chamada.
4. Existem headers duplicados
Evite definir Content-Type tanto em .headers.content_type quanto em .extra_headers. Duplicidade pode causar rejeição pelo servidor ou comportamento ambíguo em proxies.
5. Você precisa da API de baixo nível
fetch resolve GET, POST e boa parte das integrações REST. Streaming de upload, controle fino da conexão ou protocolos long-lived podem exigir APIs de nível mais baixo, que são mais sensíveis à versão. Nesse caso, consulte a documentação exata do release e mantenha esse código isolado em um adaptador pequeno.
Checklist para headers HTTP em Zig
- Executei
zig versione usei documentação do mesmo release. - Troquei
req.headers.appendpor opções compatíveis com a versão atual. - Usei
extra_headerspara headers customizados. - Usei o campo tipado para
Content-Typequando disponível. - Mantive buffers dinâmicos vivos durante a requisição.
- Não registrei token, cookie, API key ou header
Authorization. - Validei o status HTTP antes de interpretar JSON.
- Limitei o tamanho da resposta conforme o risco da integração.
- Reutilizei
std.http.Clientquando faço várias chamadas. - Fixei a versão do Zig no CI e no ambiente de desenvolvimento.
Conclusão
O erro em req.headers.append quase sempre é um sinal de exemplo desatualizado, não de ausência de suporte a headers no Zig. Para requisições comuns, passe os cabeçalhos em extra_headers dentro das opções de std.http.Client.fetch; use campos tipados para headers conhecidos e mantenha valores dinâmicos válidos durante toda a chamada.
A lição mais importante é não migrar std.http linha por linha entre versões. Migre a operação inteira — criação, headers, body, armazenamento da resposta e validação de status — usando uma única API coerente com o release do projeto.
Para continuar, leia Zig HTTP Client: GET, POST, JSON e APIs REST, a receita de HTTP GET com std.http.Client e o guia de tratamento de erros em Zig.