HTTP para testes de API: métodos, semântica e efeitos colaterais

Capítulo 2

Tempo estimado de leitura: 10 minutos

+ Exercício

Métodos HTTP: semântica, segurança (safe) e idempotência

Em testes de API, não basta verificar se a resposta “funciona”: é essencial validar se o método HTTP usado é coerente com a intenção da operação e se os efeitos no estado do servidor seguem a semântica esperada. Isso reduz bugs, inconsistências e comportamentos perigosos (como um GET que altera dados).

Conceitos-chave para testar

  • Semântica do método: o que o método significa (ler, criar, substituir, modificar parcialmente, remover).
  • Segurança (safe methods): métodos que não devem alterar o estado do servidor quando chamados (ex.: GET). Em geral, HEAD e OPTIONS também são safe, mas aqui o foco é GET.
  • Idempotência: repetir a mesma requisição N vezes deve produzir o mesmo estado final no servidor. A resposta pode variar (ex.: timestamps), mas o estado final deve ser equivalente.
MétodoIntençãoSafe?Idempotente?Efeito esperado no servidor
GETConsultar recurso(s)SimSimNão altera estado
POSTCriar (ou acionar processamento)NãoNão (em geral)Cria novo recurso ou inicia ação
PUTSubstituir recurso (ou criar em URI conhecida)NãoSimRecurso fica exatamente como o payload define
PATCHAtualização parcialNãoDepende (pode ser, mas nem sempre)Altera apenas campos/partes informadas
DELETERemover recursoNãoSim (idealmente)Recurso deixa de existir (ou fica marcado como removido)

GET: leitura sem efeitos colaterais

Quando usar

  • Buscar um recurso: GET /users/123
  • Listar recursos com filtros/paginação: GET /users?status=active&page=2

Efeitos esperados no estado do servidor

  • Não deve criar, atualizar ou remover dados.
  • Não deve disparar ações com efeitos persistentes (ex.: “confirmar compra”, “enviar e-mail”).

Exemplo de requisição e resposta esperada

GET /users/123 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
ETag: "u123-v7"

{
  "id": 123,
  "name": "Ana",
  "email": "ana@exemplo.com",
  "status": "active"
}

Checklist de validação (GET)

  • Semântica: endpoint retorna representação do recurso/coleção.
  • Safe: chamar o GET repetidas vezes não altera dados (ver passo a passo abaixo).
  • Status codes: 200 para sucesso; 404 se não existe; 400 para parâmetros inválidos; 401/403 para autenticação/autorização.
  • Cacheabilidade (quando aplicável): presença de ETag e suporte a If-None-Match retornando 304 Not Modified.
  • Consistência: campos obrigatórios presentes e tipos corretos; ausência de dados sensíveis indevidos.

Passo a passo prático: como testar que GET não altera estado

  1. Escolha um recurso com estado observável (ex.: status, updatedAt, contador, etc.).
  2. Faça um GET e registre a resposta completa.
  3. Faça o mesmo GET novamente (idealmente 2–3 vezes).
  4. Valide que não houve alteração em campos que indicam mutação (ex.: updatedAt não muda; contadores não incrementam; não surgem novos registros).
  5. Se existir endpoint de auditoria/logs, valide que não houve evento de escrita associado ao GET.

Observação: métricas internas (telemetria) podem ser atualizadas sem violar a semântica, mas qualquer alteração em dados de domínio (ex.: pedido, usuário, saldo) é um problema.

POST: criação e ações não idempotentes

Quando usar

  • Criar um recurso em uma coleção: POST /orders
  • Disparar uma ação/processamento: POST /payments/charge (quando não se encaixa em CRUD simples)

Efeitos esperados no estado do servidor

  • Normalmente cria um novo recurso (novo identificador).
  • Pode iniciar um processamento assíncrono (gerando um “job”, evento, etc.).

Exemplo: criar recurso e retornar localização/identificador

POST /orders HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json

{
  "customerId": 10,
  "items": [
    {"sku": "ABC", "qty": 2}
  ]
}
HTTP/1.1 201 Created
Content-Type: application/json
Location: /orders/987

{
  "id": 987,
  "status": "created",
  "customerId": 10,
  "items": [{"sku": "ABC", "qty": 2}]
}

Checklist de validação (POST)

  • Criação: retorna 201 Created quando cria recurso; corpo inclui id (ou equivalente).
  • Location: header Location aponta para o novo recurso (quando aplicável).
  • Validação de entrada: payload inválido retorna 400 com detalhes úteis; campos obrigatórios são exigidos.
  • Não idempotência: repetir o mesmo POST pode criar duplicados; se o sistema precisa evitar duplicidade, deve haver estratégia (ex.: chave de idempotência) e isso deve ser testado.
  • Segurança: requer autenticação/autorização adequadas; não permite criação em nome de outro usuário sem permissão.

Passo a passo prático: como testar comportamento não idempotente (e duplicidade)

  1. Envie um POST válido e capture o id retornado.
  2. Envie o mesmo POST novamente.
  3. Verifique se um novo recurso foi criado (novo id) ou se a API bloqueia duplicidade (ex.: 409 Conflict ou retorno do mesmo resultado via idempotency key, se existir).
  4. Se a API tiver suporte a chave de idempotência (ex.: header Idempotency-Key), repita o POST com a mesma chave e valide que o estado final não duplica (mesmo id ou mesma operação reaproveitada).

PUT: substituição completa (e idempotência)

Quando usar

  • Substituir completamente um recurso conhecido: PUT /users/123
  • Atualizar de forma que o servidor passe a refletir exatamente o payload enviado.

Efeitos esperados no estado do servidor

  • O recurso final deve ser equivalente ao payload (campos ausentes podem ser removidos/resetados, dependendo do contrato).
  • Repetir o mesmo PUT deve manter o mesmo estado final (idempotente).

Exemplo: substituir usuário

PUT /users/123 HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json

{
  "id": 123,
  "name": "Ana Souza",
  "email": "ana@exemplo.com",
  "status": "active"
}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "Ana Souza",
  "email": "ana@exemplo.com",
  "status": "active"
}

Checklist de validação (PUT)

  • Substituição: após o PUT, um GET deve refletir exatamente o recurso atualizado.
  • Idempotência: repetir o mesmo PUT não deve gerar mudanças adicionais (nem criar versões extras, nem duplicar efeitos).
  • Campos ausentes: comportamento definido e testado (ex.: ausentes são removidos? mantidos? rejeitados?).
  • Status codes: 200 ou 204 em sucesso; 404 se o recurso não existe (ou 201 se o contrato permitir criação via PUT em URI conhecida).

Passo a passo prático: como testar idempotência do PUT

  1. Faça GET do recurso e guarde o estado atual.
  2. Execute PUT com um payload completo.
  3. Faça GET e valide que o estado corresponde ao payload.
  4. Execute o mesmo PUT novamente.
  5. Faça GET e valide que o estado permanece igual ao passo 3 (sem alterações adicionais).

PATCH: atualização parcial (e armadilhas de idempotência)

Quando usar

  • Alterar apenas alguns campos sem enviar o recurso inteiro: PATCH /users/123
  • Operações parciais que não representam uma substituição completa.

Efeitos esperados no estado do servidor

  • Somente os campos/partes enviados devem mudar; o restante deve permanecer igual.
  • Idempotência depende do tipo de patch: “setar valor” tende a ser idempotente; “incrementar contador” não é.

Cenários práticos: PUT vs PATCH

CenárioMelhor escolhaPor quê
Atualizar apenas status de um usuárioPATCHEvita enviar o recurso inteiro; altera campo específico
Cliente possui representação completa e quer “sincronizar” o recursoPUTSubstituição completa reduz ambiguidade
Atualizar perfil inteiro e remover campos que não existem maisPUTSemântica de substituição permite remoção/reset
Aplicar operação do tipo “incrementar pontos”PATCH (não idempotente)É uma operação parcial com efeito acumulativo

Exemplo 1 (PATCH idempotente): setar um campo

PATCH /users/123 HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json

{
  "status": "inactive"
}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "Ana Souza",
  "email": "ana@exemplo.com",
  "status": "inactive"
}

Repetir esse PATCH tende a manter o mesmo estado final (idempotente), pois “status=inactive” não acumula efeito.

Exemplo 2 (PATCH não idempotente): operação incremental

PATCH /users/123/points HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json

{
  "op": "increment",
  "value": 10
}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "points": 110
}

Repetir a mesma requisição incrementa novamente (110, 120, 130...), portanto não é idempotente. Em testes, isso deve ser intencional e documentado.

Checklist de validação (PATCH)

  • Parcialidade: campos não enviados permanecem inalterados (validar via GET antes/depois).
  • Validação: rejeita campos desconhecidos ou tipos inválidos conforme contrato.
  • Idempotência: identificar se o patch é do tipo “set” (idempotente) ou “operação” (pode não ser). Testar repetição e observar estado final.
  • Conflitos: se houver controle de concorrência (ex.: ETag), validar 412 Precondition Failed quando o cliente atualiza com versão desatualizada.

Passo a passo prático: como testar PUT vs PATCH no mesmo recurso

  1. Faça GET do recurso e salve a representação completa.
  2. Execute PATCH alterando um único campo (ex.: status).
  3. Faça GET e valide que apenas esse campo mudou.
  4. Agora execute PUT com a representação completa original (ou uma nova completa) e valide que o recurso foi substituído conforme o payload.
  5. Se o contrato define comportamento para campos ausentes no PUT, envie um PUT omitindo um campo opcional e valide se ele foi removido/resetado ou mantido (conforme especificação).

DELETE: remoção e idempotência observável

Quando usar

  • Remover um recurso: DELETE /orders/987

Efeitos esperados no estado do servidor

  • O recurso deve deixar de existir ou ficar inacessível (em soft delete, pode ficar marcado como removido).
  • Repetir DELETE deve manter o estado final “removido” (idempotente), embora a resposta possa variar.

Exemplo de requisição e respostas esperadas

DELETE /orders/987 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
HTTP/1.1 204 No Content

Após isso:

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

GET /orders/987 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": "not_found",
  "message": "Order 987 not found"
}

Checklist de validação (DELETE)

  • Remoção: GET posterior não retorna mais o recurso (ou retorna estado “deleted”, conforme contrato).
  • Status codes: 204 (comum) ou 200 com corpo; para recurso inexistente, pode retornar 404 ou 204 (varia por contrato, mas deve ser consistente).
  • Idempotência: repetir DELETE não deve “ressuscitar” recurso nem causar efeitos adicionais.
  • Autorização: apenas perfis permitidos podem remover.

Passo a passo prático: como testar idempotência do DELETE

  1. Crie (ou selecione) um recurso existente e confirme com GET.
  2. Execute DELETE e valide o status (204 ou 200).
  3. Execute GET e valide que não existe/está removido.
  4. Execute DELETE novamente e valide que o comportamento é consistente com o contrato (ex.: 404 ou 204), sem recriar nem alterar outros dados.

Roteiro de testes: segurança (safe) e idempotência por método

Teste de segurança (safe) para GET

  • Execute GET repetido e compare: updatedAt, contadores de domínio, listas de itens, saldos.
  • Se houver auditoria, valide ausência de eventos de escrita.
  • Verifique que parâmetros de consulta não disparam ações (ex.: ?confirm=true não deve confirmar nada).

Teste de idempotência para PUT e DELETE

  • Repita a mesma requisição 2–3 vezes.
  • Valide que o estado final do recurso é o mesmo após cada repetição.
  • Se a resposta variar, garanta que a variação é aceitável (ex.: cabeçalhos de data), mas o estado persistido não muda.

Teste de (não) idempotência para POST e PATCH

  • POST: repetir deve criar duplicados, a menos que exista mecanismo explícito para evitar (ex.: chave de idempotência). Teste ambos os comportamentos conforme contrato.
  • PATCH: classifique o endpoint como “set” (tende a ser idempotente) ou “operação” (pode não ser). Repita e observe se acumula efeito.

Exemplos adicionais de respostas esperadas em cenários comuns

GET com recurso inexistente

GET /users/999999 HTTP/1.1
Host: api.exemplo.com
Accept: application/json
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": "not_found",
  "message": "User not found"
}

POST com validação falhando

POST /orders HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Accept: application/json

{
  "customerId": null,
  "items": []
}
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "validation_error",
  "fields": {
    "customerId": "required",
    "items": "must_have_at_least_one_item"
  }
}

PUT com conflito de versão (quando há ETag)

PUT /users/123 HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
If-Match: "u123-v6"

{
  "id": 123,
  "name": "Ana Souza",
  "email": "ana@exemplo.com",
  "status": "active"
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json

{
  "error": "precondition_failed",
  "message": "Resource version mismatch"
}

Agora responda o exercício sobre o conteúdo:

Ao validar idempotência em testes de API, o que deve permanecer equivalente quando a mesma requisição é repetida N vezes (mesmo que a resposta varie em detalhes como timestamps)?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Idempotência significa que repetir a mesma requisição deve levar ao mesmo estado final no servidor. A resposta pode variar (ex.: timestamps), mas o estado persistido deve permanecer equivalente.

Próximo capitúlo

Headers e negociação de conteúdo em testes de API (Content-Type e Accept)

Arrow Right Icon
Capa do Ebook gratuito Testes de API: Conceitos Essenciais (REST, HTTP, Status Codes e Contratos)
13%

Testes de API: Conceitos Essenciais (REST, HTTP, Status Codes e Contratos)

Novo curso

15 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.