Por que headers importam em testes de API
Headers são metadados da requisição e da resposta. Eles controlam como o servidor deve interpretar o corpo (payload), qual formato o cliente aceita receber, como autenticar, como cachear, como correlacionar chamadas e como aplicar regras específicas do domínio. Em testes de API, validar headers é tão importante quanto validar o body, porque muitos comportamentos (sucesso, erro, cache, compatibilidade) dependem deles.
O que testar em headers (checklist rápido)
- Requisição:
Content-Type,Accept,Authorization,User-Agent,Cache-Control,If-None-Match,Correlation-Ide headers customizados. - Resposta:
Content-Type(incluindocharset),ETag,Cache-Control,Vary,WWW-Authenticate(quando aplicável), e eco/propagação de correlação (quando o sistema define esse contrato).
Content-Type: como o servidor interpreta o corpo
Content-Type descreve o tipo de mídia do corpo enviado na requisição (e também aparece na resposta para indicar o formato retornado). Em testes, ele é crucial para validar parsing, validação e erros de mídia.
Casos comuns de Content-Type
application/json: payload JSON.application/xml: payload XML.application/x-www-form-urlencoded: formulário simples.multipart/form-data: upload de arquivos e campos.text/plain: texto puro.
Charset e encoding (o que validar)
É comum ver Content-Type: application/json; charset=utf-8. O charset define a codificação de caracteres (por exemplo, UTF-8). Em APIs modernas, UTF-8 é o padrão de fato, mas seu teste deve garantir consistência quando o contrato exige.
- Validar resposta: o
Content-Typeretornado deve corresponder ao formato real do body (ex.: JSON válido quando dizapplication/json). - Validar caracteres: strings com acentos/emoji devem chegar e voltar corretamente (ex.: “ação”, “café”, “São Paulo”).
- Encoding de transporte: compressão como
Content-Encoding: gzippode existir; em testes automatizados, verifique se o cliente lida com isso e se o servidor anuncia corretamente.
Erro 415 (Unsupported Media Type): quando o Content-Type é inválido
O status 415 ocorre quando o servidor não suporta o tipo de mídia enviado (ou não consegue processar o corpo com aquele Content-Type).
O que checar no teste de 415:
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
- O status code é
415. - A resposta contém mensagem/estrutura de erro conforme contrato (por exemplo,
code,message,details). - Não há efeitos colaterais (nenhum recurso criado/alterado).
# Exemplo: enviando JSON, mas declarando text/plain (provável 415 ou 400, dependendo da API) curl -i -X POST https://api.exemplo.com/pedidos -H "Content-Type: text/plain" -H "Accept: application/json" -d '{"item":"cafe","qtd":1}'Observação: algumas APIs retornam 400 quando o body não é parseável; outras retornam 415 quando o tipo de mídia é o problema. Seu teste deve refletir o contrato esperado para aquele endpoint.
Accept: o que o cliente quer receber (content negotiation)
Accept indica quais tipos de mídia o cliente aceita na resposta. Isso habilita negociação de conteúdo (content negotiation): o servidor escolhe um formato compatível com o que o cliente pediu e com o que ele consegue produzir.
Exemplos de Accept
Accept: application/json(quero JSON)Accept: application/xml(quero XML)Accept: application/json, application/xml;q=0.9(prefiro JSON, aceito XML com prioridade menor)Accept: */*(aceito qualquer coisa)
Como validar a negociação na prática
- Se o cliente envia
Accept: application/json, a resposta deve vir comContent-Typecompatível (ex.:application/json). - Se o cliente envia múltiplos tipos com
q(quality), o servidor deve escolher o mais adequado (conforme implementação/contrato). - Se o servidor não consegue produzir nenhum tipo aceito, deve retornar
406 Not Acceptable.
Erro 406 (Not Acceptable): quando não há formato compatível
406 ocorre quando o servidor não consegue responder em nenhum dos formatos solicitados em Accept.
# Exemplo: pedindo um formato que a API não suporta curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/pdf"O que checar no teste de 406:
- Status code
406. - Resposta de erro com
Content-Typeconsistente (muitas APIs retornam erros em JSON mesmo quando o Accept é inválido; isso deve estar documentado/contratado). - Mensagem clara indicando formatos suportados (quando aplicável).
Authorization: autenticação e autorização via header
Authorization carrega credenciais (por exemplo, token). Em testes, você valida tanto o comportamento de autenticação (credencial válida/inválida/ausente) quanto a autorização (permissões).
Padrões comuns
Authorization: Bearer <token>Authorization: Basic <base64(user:pass)>
Casos de teste essenciais
- Sem header: deve retornar
401(ou conforme contrato). - Token inválido/expirado:
401. - Token válido sem permissão:
403. - Formato malformado (ex.: “Bearer” sem token): erro consistente (frequentemente
401).
# Sem Authorization curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" # Token inválido curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "Authorization: Bearer token_invalido"User-Agent: identificação do cliente e comportamento condicional
User-Agent identifica o cliente (biblioteca, app, versão). Algumas APIs aplicam regras por User-Agent (bloqueio, rate limit diferenciado, compatibilidade). Em testes, isso é útil para reproduzir bugs específicos de clientes e validar políticas.
O que testar
- Se a API exige User-Agent, ausência deve gerar erro claro (não é comum, mas existe).
- Se há comportamento diferenciado por versão, valide respostas para User-Agents distintos.
curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "User-Agent: MeuClienteTeste/1.0"Cache-Control, ETag e If-None-Match: cache e respostas condicionais
Headers de cache impactam performance e consistência. Em testes, você valida se o servidor anuncia cache corretamente e se respeita requisições condicionais.
Cache-Control (resposta)
Cache-Control: no-store: não deve ser armazenado.Cache-Control: no-cache: pode armazenar, mas deve revalidar.Cache-Control: max-age=60: pode usar cache por 60s.
ETag e If-None-Match (revalidação)
ETag é um identificador da versão do recurso. O cliente pode enviar If-None-Match com a ETag recebida; se nada mudou, o servidor responde 304 Not Modified sem body.
Passo a passo: testando ETag/If-None-Match
- Faça um GET no recurso e capture o header
ETag. - Repita o GET enviando
If-None-Matchcom o valor capturado. - Valide que a resposta é
304(quando não houve mudança) e que não há body (ou body vazio, conforme implementação). - Altere o recurso (por uma operação que mude o conteúdo) e repita o GET com a ETag antiga; agora deve retornar
200com nova ETag.
# 1) Capturar ETag curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" # suponha que veio: ETag: "abc123" # 2) Requisição condicional curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "If-None-Match: \"abc123\""O que validar:
- Quando retorna
304, headers relevantes ainda podem vir (ex.:ETag,Cache-Control). - Quando retorna
200, o body corresponde ao estado atual e a ETag muda quando o recurso muda.
Correlation-Id: rastreabilidade ponta a ponta
Correlation-Id (ou variações como X-Correlation-Id) ajuda a rastrear uma requisição em logs distribuídos. Em testes, ele é útil para depuração e também pode fazer parte do contrato (por exemplo, o servidor deve ecoar o mesmo ID).
O que testar
- Enviar um
Correlation-Ide validar se a resposta ecoa o mesmo valor (quando definido). - Quando não enviado, validar se o servidor gera um e retorna (quando definido).
- Formato: UUID, string alfanumérica, tamanho máximo.
curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "Correlation-Id: 3f2a2c2e-7a7b-4b2f-9c2f-4c9b3a1c2d10"Headers customizados: regras de negócio e compatibilidade
APIs podem definir headers próprios para versionamento, idempotência, tenant, região, etc. Exemplos: X-Api-Version, Idempotency-Key, X-Tenant-Id. Em testes, trate-os como parte do contrato: presença, formato, obrigatoriedade e efeitos.
Exemplo: versionamento por header
curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "X-Api-Version: 2"Casos de teste:
- Versão suportada: resposta conforme schema esperado.
- Versão não suportada: erro consistente (frequentemente
400ou406, conforme contrato). - Ausência do header quando obrigatório: erro claro.
Exercícios práticos: variações de headers e casos negativos
Exercício 1: matriz de Content-Type vs body
Objetivo: observar como o servidor diferencia “tipo de mídia não suportado” (415) de “payload inválido” (400).
| Caso | Content-Type | Body enviado | Esperado |
|---|---|---|---|
| A | application/json | JSON válido | 2xx |
| B | application/json | JSON inválido | 400 (ou contrato) |
| C | text/plain | JSON válido | 415 (ou contrato) |
| D | (sem Content-Type) | JSON válido | 415/400 (ou contrato) |
# Caso B: JSON inválido curl -i -X POST https://api.exemplo.com/pedidos -H "Content-Type: application/json" -H "Accept: application/json" -d '{"item": "cafe", "qtd": }' # Caso C: tipo de mídia incompatível curl -i -X POST https://api.exemplo.com/pedidos -H "Content-Type: text/plain" -H "Accept: application/json" -d '{"item":"cafe","qtd":1}'Exercício 2: negociação com Accept e validação de 406
Objetivo: confirmar os formatos suportados e o comportamento quando o cliente pede algo impossível.
- Chame o endpoint com
Accept: application/jsone registre oContent-Typeda resposta. - Repita com
Accept: application/xml(se a API suportar) e compare. - Envie
Accept: application/pdfe valide406. - Envie
Accept: */*e valide que retorna um formato padrão (geralmente JSON).
curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/pdf" curl -i https://api.exemplo.com/pedidos/123 -H "Accept: */*"Exercício 3: charset e caracteres especiais
Objetivo: validar que o servidor interpreta e devolve caracteres corretamente.
- Envie um payload com acentos e caracteres especiais.
- Valide que o valor persistido/retornado é idêntico.
- Valide o
Content-Typeda resposta comcharsetesperado (quando aplicável).
curl -i -X POST https://api.exemplo.com/clientes -H "Content-Type: application/json; charset=utf-8" -H "Accept: application/json" -d '{"nome":"João da Silva","cidade":"São Paulo","observacao":"café"}'Exercício 4: Authorization negativo e mensagens consistentes
Objetivo: garantir que falhas de autenticação/autorização são previsíveis e não vazam detalhes sensíveis.
- Sem
Authorization→ validar401e, se houver,WWW-Authenticate. - Com token inválido → validar
401. - Com token válido sem permissão → validar
403.
curl -i https://api.exemplo.com/admin/relatorios -H "Accept: application/json" curl -i https://api.exemplo.com/admin/relatorios -H "Accept: application/json" -H "Authorization: Bearer invalido"Exercício 5: ETag/If-None-Match e 304
Objetivo: validar cache condicional e ausência de body em 304.
- Faça GET e capture
ETag. - Reenvie GET com
If-None-Matche valide304. - Altere o recurso e valide que volta a responder
200com nova ETag.
Exercício 6: Correlation-Id e propagação
Objetivo: validar rastreabilidade.
- Envie um
Correlation-Idfixo. - Valide se a resposta contém o mesmo header e valor (quando contratual).
- Envie requests concorrentes com IDs diferentes e valide que não há mistura.
curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "Correlation-Id: teste-req-001" curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "Correlation-Id: teste-req-002"Exercício 7: headers customizados (casos negativos)
Objetivo: validar robustez do contrato para headers específicos do domínio.
- Header obrigatório ausente (ex.:
X-Tenant-Id) → erro esperado. - Header com formato inválido (ex.: tamanho excedido, caracteres proibidos) → erro esperado.
- Header com valor desconhecido (ex.: tenant inexistente) → erro esperado (frequentemente
404ou403, conforme contrato).
curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "X-Tenant-Id: " curl -i https://api.exemplo.com/pedidos/123 -H "Accept: application/json" -H "X-Tenant-Id: tenant_inexistente"