O que é HTTP e por que ele importa em testes de APIs REST
HTTP (Hypertext Transfer Protocol) é o protocolo de comunicação mais comum entre clientes e servidores na Web. Em APIs REST, ele define como uma requisição é enviada (método, URL, cabeçalhos e corpo) e como uma resposta é devolvida (status code, cabeçalhos e corpo). Para testes de API, entender HTTP é essencial porque a maior parte dos defeitos e comportamentos inesperados aparece exatamente nesses elementos: um método incorreto, um status code incoerente, um header ausente, um corpo malformado, cache indevido, autenticação mal aplicada ou negociação de conteúdo errada.
Em termos práticos, quando você testa uma API REST, você está validando um contrato HTTP: “quando eu envio X (requisição), eu recebo Y (resposta)”. Esse contrato inclui regras explícitas (documentação, OpenAPI, padrões internos) e implícitas (semântica dos métodos, códigos de status, idempotência, cacheabilidade). Quanto mais você domina HTTP, mais rápido você identifica se um problema é de dados, de regra de negócio, de roteamento, de autenticação ou de infraestrutura.
Estrutura de uma requisição HTTP
Uma requisição HTTP é composta por: método, URL (com path e query string), cabeçalhos (headers) e, opcionalmente, corpo (body). Em testes, você deve enxergar cada parte como um “ponto de controle” com validações específicas.
Método HTTP (verbo)
O método indica a intenção da operação. Em REST, os mais comuns são GET, POST, PUT, PATCH e DELETE. A escolha correta do método afeta comportamento esperado, idempotência e até cache.
- GET: leitura/consulta. Não deve alterar estado no servidor. Normalmente não tem body (apesar de tecnicamente possível). Deve ser idempotente e pode ser cacheável.
- POST: criação ou execução de uma ação que gera efeito. Não é idempotente por padrão (enviar duas vezes pode criar dois recursos).
- PUT: substituição completa de um recurso em uma URL conhecida. Deve ser idempotente (enviar o mesmo payload repetidas vezes resulta no mesmo estado final).
- PATCH: atualização parcial. Pode ou não ser idempotente dependendo da semântica do patch.
- DELETE: remoção. Deve ser idempotente (deletar duas vezes tende a manter o recurso ausente), mas a resposta pode variar (por exemplo, 404 na segunda tentativa).
Em testes, um erro comum é a API aceitar métodos indevidos (por exemplo, permitir DELETE onde deveria bloquear) ou responder com status code incoerente (por exemplo, retornar 200 em um POST que falhou por validação).
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
URL: esquema, host, path e query string
A URL define o destino. Em APIs, normalmente você terá um esquema (https), um host (api.exemplo.com), um path (por exemplo, /v1/users/123) e parâmetros de query (por exemplo, ?active=true&page=2). Em testes, verifique: versionamento no path, roteamento correto, encoding de caracteres especiais, e se a API diferencia corretamente path params e query params.
- Path params costumam identificar recursos: /users/{id}.
- Query params costumam filtrar, paginar, ordenar: /users?status=active&sort=name&page=1.
Validações típicas: parâmetros obrigatórios ausentes, tipos inválidos (string onde deveria ser número), limites (page negativo), e comportamento quando parâmetros desconhecidos são enviados (a API ignora, rejeita com 400, ou falha com 500?).
Headers: metadados e controle de comportamento
Headers carregam metadados e instruções. Em testes de API, headers são fonte frequente de bugs, principalmente em autenticação, negociação de conteúdo, cache e rastreabilidade.
- Content-Type: indica o formato do body enviado pelo cliente (por exemplo, application/json). Se você envia JSON sem Content-Type correto, a API pode interpretar errado ou rejeitar.
- Accept: indica o formato esperado na resposta (por exemplo, application/json). Útil para testar negociação de conteúdo e respostas 406 (Not Acceptable) quando o servidor não suporta o formato solicitado.
- Authorization: credenciais (por exemplo, Bearer token). Testes devem cobrir ausência, token inválido, token expirado e permissões insuficientes.
- Cache-Control, ETag, If-None-Match: relacionados a cache e validação condicional. Importante para GETs que podem ser cacheados.
- Correlation-Id/X-Request-Id: rastreamento. Ajuda a debugar e também pode ser requisito de observabilidade.
Um ponto prático: muitos testes falham não por regra de negócio, mas por header faltando. Por isso, ao desenhar casos, inclua variações com headers ausentes, duplicados, com valores inválidos e com capitalização diferente (HTTP headers são case-insensitive, mas implementações podem ter bugs).
Body: payload de entrada
O body é onde você envia dados para criação/atualização (POST/PUT/PATCH). Em testes, você valida: campos obrigatórios, tipos, limites, formato, campos extras, e consistência entre campos (por exemplo, startDate menor que endDate). Também é importante testar como a API lida com payload vazio, payload grande, e caracteres especiais.
Mesmo quando o body é JSON, o teste HTTP não é apenas “o JSON está certo”; é também “o servidor interpretou corretamente o Content-Type”, “o servidor retorna 415 (Unsupported Media Type) quando o tipo é inválido”, e “o servidor retorna 400 (Bad Request) quando o JSON é malformado”.
Estrutura de uma resposta HTTP
Uma resposta HTTP contém: status code, headers e body. Em testes, você deve validar coerência entre esses elementos. Por exemplo, uma resposta 204 (No Content) não deve trazer body; uma resposta 201 (Created) costuma indicar criação e pode trazer header Location apontando para o recurso criado.
Status codes: semântica e expectativas
Status codes são a linguagem padrão para indicar resultado. Em testes, não basta checar “é 200”; você deve checar se o código é o mais adequado para o cenário.
- 2xx (sucesso): 200 OK (sucesso geral), 201 Created (criação), 202 Accepted (processamento assíncrono), 204 No Content (sucesso sem corpo).
- 3xx (redirecionamento): menos comum em APIs, mas pode aparecer em migrações, proxies ou endpoints antigos.
- 4xx (erro do cliente): 400 Bad Request (payload/parâmetros inválidos), 401 Unauthorized (sem autenticação ou inválida), 403 Forbidden (autenticado, mas sem permissão), 404 Not Found (recurso inexistente), 409 Conflict (conflito, como duplicidade), 422 Unprocessable Entity (validação semântica), 429 Too Many Requests (rate limit).
- 5xx (erro do servidor): 500 Internal Server Error, 502/503/504 em cenários de gateway/indisponibilidade/timeout.
Um teste bem desenhado diferencia 401 de 403, 400 de 422, 404 de 410 (Gone, quando aplicável). Também verifica se a API não “mascara” erros retornando 200 com um campo de erro no body, o que dificulta automação e observabilidade.
Headers de resposta: o que observar
Além do body, headers de resposta trazem informações críticas. Exemplos: Content-Type (formato retornado), Cache-Control (regras de cache), ETag (controle de versão para cache/concorrência), Location (em 201), Retry-After (em 429/503), e headers de segurança (como Strict-Transport-Security, dependendo do contexto).
Em testes, verifique se Content-Type condiz com o que foi negociado via Accept, e se endpoints sensíveis não são indevidamente cacheados. Para APIs públicas, rate limiting e headers associados podem ser requisitos formais.
Semântica REST aplicada ao HTTP: idempotência e segurança
Dois conceitos de HTTP são especialmente úteis em testes: “safe” (seguro) e “idempotente”. Um método safe (como GET) não deve causar efeitos colaterais no servidor. Um método idempotente (como GET, PUT, DELETE) deve produzir o mesmo resultado final quando repetido com os mesmos parâmetros.
Como isso vira teste? Você pode repetir a mesma requisição e comparar: status code, efeitos no estado e, quando aplicável, consistência do recurso. Por exemplo, um PUT repetido deve manter o recurso no mesmo estado. Um DELETE repetido não deve recriar nada; pode retornar 204 na primeira vez e 404 na segunda, mas não deve retornar 500.
Negociação de conteúdo: Accept e Content-Type na prática
Negociação de conteúdo é o mecanismo pelo qual cliente e servidor acordam formatos. O cliente diz o que envia (Content-Type) e o que aceita receber (Accept). Em APIs REST, o mais comum é application/json, mas você pode encontrar text/plain, application/xml, multipart/form-data e application/x-www-form-urlencoded.
Casos de teste úteis: enviar Content-Type incorreto e esperar 415; enviar Accept não suportado e esperar 406; omitir Accept e verificar o padrão; enviar charset (application/json; charset=utf-8) e verificar se o servidor aceita.
Autenticação e autorização em nível HTTP
Mesmo sem entrar em detalhes de ferramentas, do ponto de vista HTTP você testa autenticação e autorização observando headers e status codes. A autenticação geralmente aparece no header Authorization. A autorização se manifesta quando o servidor decide se aquele usuário pode acessar o recurso.
- Sem Authorization: normalmente 401.
- Authorization inválido/expirado: 401.
- Authorization válido, mas sem permissão: 403.
- Recurso não existe ou não visível: algumas APIs retornam 404 para não revelar existência (comportamento deliberado). Isso precisa estar alinhado com o contrato.
Também é comum testar escopos/roles: o mesmo endpoint pode retornar 200 para um perfil e 403 para outro. Em HTTP, isso se traduz em variar o token/credencial e validar o status code e a ausência de dados sensíveis.
Cache e validação condicional: ETag e 304
Para endpoints GET, cache pode melhorar performance, mas também pode causar inconsistências se mal configurado. HTTP oferece mecanismos como ETag e If-None-Match. O servidor retorna um ETag representando a versão do recurso. O cliente pode enviar If-None-Match com esse valor; se nada mudou, o servidor responde 304 Not Modified sem body.
Testes práticos: fazer um GET e capturar o ETag; repetir o GET com If-None-Match e esperar 304; alterar o recurso (via PUT/PATCH) e repetir o GET condicional para esperar 200 com novo ETag. Também verifique Cache-Control para garantir que dados sensíveis não sejam cacheados por proxies.
Paginação, ordenação e filtros via query string
Muitas APIs expõem listas com paginação. Em HTTP, isso costuma ser feito com query params como page, limit, offset, cursor, sort e filtros. Testes devem cobrir: limites máximos, valores inválidos, comportamento em páginas além do fim, ordenação estável e consistência quando filtros são combinados.
Exemplos de cenários: page=0 (a API aceita ou retorna 400?), limit muito alto (retorna 400, 422 ou aplica um teto?), sort por campo inexistente (400?), filtro com caracteres especiais (encoding correto), e parâmetros repetidos (status=active&status=blocked) quando a API suporta múltiplos valores.
Passo a passo prático: desenhando casos de teste HTTP para um endpoint REST
O objetivo aqui é transformar fundamentos de HTTP em um roteiro repetível. Suponha um endpoint de usuários: GET /v1/users/{id}, POST /v1/users, PUT /v1/users/{id}, PATCH /v1/users/{id}, DELETE /v1/users/{id}. O passo a passo abaixo foca no que validar em HTTP, independentemente da ferramenta.
Passo 1: Defina o contrato esperado (método, URL, headers, status codes)
Liste para cada operação: método correto, path, query params aceitos, headers obrigatórios (Content-Type, Accept, Authorization), e status codes esperados para sucesso e falhas comuns. Exemplo: POST /v1/users com Content-Type application/json deve retornar 201; se faltar campo obrigatório, retornar 400 ou 422 (conforme padrão do time); se token ausente, 401.
Passo 2: Crie casos positivos (happy path) com validações de semântica
Para GET /v1/users/123: esperar 200 e Content-Type coerente. Para POST: esperar 201 e, se aplicável, header Location apontando para /v1/users/{novoId}. Para PUT: repetir a mesma requisição duas vezes e validar idempotência (o estado final não muda). Para DELETE: validar que após deletar, um GET retorna 404 (ou 410, conforme contrato).
Passo 3: Cubra erros 4xx por variação controlada de entrada
Monte uma matriz simples de variações: método errado, header ausente, header inválido, query param inválido, body inválido. Exemplos: enviar POST sem Content-Type e observar se a API retorna 415 ou 400; enviar Accept application/xml quando só há JSON e esperar 406; enviar id com formato inválido (por exemplo, letras quando deveria ser numérico) e esperar 400; enviar body com JSON malformado e esperar 400.
Passo 4: Teste autenticação e autorização via status code
Execute o mesmo endpoint com: sem Authorization (esperar 401), com credencial inválida (401), com credencial válida mas sem permissão (403). Se a API adota “404 para recurso não autorizado”, registre isso como regra e valide consistência entre endpoints.
Passo 5: Verifique headers de resposta e comportamentos não-funcionais observáveis
Valide Content-Type, presença de headers de rastreio (se exigidos), e comportamento de cache (Cache-Control, ETag). Para endpoints listáveis, valide paginação e limites. Para endpoints com rate limit, provoque múltiplas requisições e verifique 429 e Retry-After (quando aplicável).
Passo 6: Modele testes de concorrência e conflito (409) quando houver atualização
Conflitos aparecem quando há regras de unicidade (por exemplo, e-mail único) ou controle de versão. Um teste típico: criar usuário com e-mail X (201), tentar criar outro com o mesmo e-mail (esperar 409 Conflict). Se a API usa ETag para controle de concorrência, você pode testar If-Match: atualizar com um ETag antigo e esperar 412 Precondition Failed (se suportado).
Exemplos de mensagens HTTP (requisição e resposta)
Os exemplos abaixo ajudam a visualizar o que você valida em testes. Adapte paths e campos ao seu domínio.
Exemplo 1: GET com negociação de conteúdo e ETag
GET /v1/users/123 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
Authorization: Bearer <token>
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
ETag: "u123-v5"
Cache-Control: private, max-age=0
{ "id": 123, "name": "Ana" }Validações: status 200, Content-Type JSON, ETag presente (se a API usa), Cache-Control adequado (por exemplo, private para dados de usuário).
Exemplo 2: GET condicional retornando 304
GET /v1/users/123 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
Authorization: Bearer <token>
If-None-Match: "u123-v5"
HTTP/1.1 304 Not Modified
ETag: "u123-v5"Validações: 304 sem body, ETag consistente. Se vier body, pode indicar implementação incorreta.
Exemplo 3: POST criando recurso com 201 e Location
POST /v1/users HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
{ "name": "Ana", "email": "ana@exemplo.com" }
HTTP/1.1 201 Created
Content-Type: application/json
Location: /v1/users/987
{ "id": 987, "name": "Ana", "email": "ana@exemplo.com" }Validações: 201, Location apontando para o recurso, e coerência entre body e Location. Se a API retorna 200 em criação, isso pode ser aceitável, mas deve ser consistente e documentado.
Exemplo 4: Erro de validação (400 ou 422)
POST /v1/users HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
{ "name": "" }
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{ "error": "VALIDATION_ERROR", "fields": { "email": "required", "name": "minLength" } }Validações: status code de validação conforme padrão, Content-Type coerente, e corpo de erro com estrutura previsível para automação.
Checklist rápido de fundamentos HTTP aplicados a testes
- O método usado é o correto e respeita semântica (GET não altera estado; PUT/DELETE idempotentes)?
- URL e parâmetros (path/query) são validados corretamente (tipos, limites, encoding)?
- Headers obrigatórios estão presentes (Content-Type, Accept, Authorization) e a API responde com 401/403/415/406 quando apropriado?
- Status codes são coerentes com o resultado (201 em criação, 204 sem body, 409 em conflito, 429 em rate limit)?
- Headers de resposta fazem sentido (Content-Type, Location, Cache-Control, ETag, Retry-After)?
- Erros 4xx retornam mensagens estruturadas e não “200 com erro no body”?
- Cache e validação condicional (ETag/If-None-Match) funcionam quando implementados?
- Paginação e filtros via query string têm comportamento consistente e previsível?