Uma resposta 500 para input inválido é sempre um bug: o servidor deveria retornar 4xx, não travar. Um 403 ausente é um bypass de autorização. Se um usuário comum acessa um endpoint de admin e recebe 200 em vez de 403, o controle de acesso não está funcionando.

Como os status codes são organizados

Os status codes HTTP são números de três dígitos organizados em cinco classes:

| Faixa | Classe | Significado |

|-------|--------|-------------|

| 1xx | Informativo | Requisição recebida, processamento em andamento |

| 2xx | Sucesso | Requisição concluída com êxito |

| 3xx | Redirecionamento | O cliente precisa tomar outra ação (geralmente seguir o redirect) |

| 4xx | Erro do cliente | A requisição tem um problema: o cliente enviou algo errado |

| 5xx | Erro do servidor | A requisição era válida: o servidor falhou em processá-la |

O primeiro dígito diz a categoria. 4xx = sua requisição estava errada. 5xx = o servidor quebrou.

2xx: códigos de sucesso

200 OK

O código de sucesso mais comum. A requisição funcionou e há conteúdo na resposta.

Usado para:
  • Requisições GET que retornam dados
  • Requisições POST que não criam um novo recurso (como uma busca)
  • Atualizações via PUT/PATCH
O que verificar nos testes:
  • O corpo da resposta contém os dados esperados
  • A resposta está no formato correto (JSON, XML)
  • Os campos obrigatórios estão presentes

201 Created

Um recurso foi criado com sucesso. Deve ser retornado para requisições POST que criam novos itens.

O que verificar:
  • A resposta inclui o recurso criado com seu novo ID
  • O header Location frequentemente aponta para a URL do novo recurso
  • POST /users201 com { id: 123, email: "...", ... }
Bug comum a capturar: a API retorna 200 em vez de 201 para endpoints de criação. Tecnicamente funciona, mas está semanticamente errado e pode confundir os consumidores da API.

204 No Content

Sucesso, mas nada a retornar. Usado para requisições DELETE e algumas respostas de PUT/PATCH.

O que verificar:
  • O corpo da resposta está vazio (algumas APIs retornam corpo incorretamente com 204)
  • O recurso foi de fato deletado (faça um GET para confirmar)

206 Partial Content

Retornado quando apenas parte de um recurso é enviada (downloads em partes, streaming de vídeo). Relevante principalmente para testar downloads de arquivo e streaming de mídia.

3xx: códigos de redirecionamento

301 Moved Permanently

O recurso foi movido permanentemente para uma nova URL. Buscadores atualizam seus índices para 301.

Relevância para testes: verifique se URLs antigas redirecionam corretamente, se redirects de HTTP para HTTPS são 301 (não 302), e se os destinos dos redirects carregam corretamente.

302 Found (Redirect Temporário)

O recurso está temporariamente em outra URL. Usado para redirects de login ("vá aqui agora, a URL original ainda é válida").

304 Not Modified

O cliente tem uma versão em cache e ela ainda é atual: nenhum conteúdo é enviado, use o cache. Você vai ver isso na aba Network do navegador para assets estáticos.

Relevância para testes: se você está testando comportamento de cache, 304 significa que o cache está funcionando. Se você está vendo 304 para dados que deveriam ter mudado, há um bug de cache.

4xx: códigos de erro do cliente

Esses significam que a sua requisição tinha um problema: dados ruins, auth ausente, URL errada.

400 Bad Request

O servidor não conseguiu entender a requisição. Geralmente significa sintaxe malformada, JSON inválido ou erro de validação.

Quando você deve ver 400:
  • JSON inválido no corpo da requisição
  • Header obrigatório ausente
  • URL malformada
O que verificar nos testes:
  • Retorna mensagem de erro útil explicando o problema
  • Não revela detalhes internos (stack traces)
  • Retorna 400, não 500 (500 para input inválido é um bug do servidor)

401 Unauthorized

A requisição não tem credenciais de autenticação válidas. "Você não está logado" ou "seu token expirou."

Diferença do 403: 401 = não autenticado (quem é você?). 403 = autenticado mas sem permissão (sei quem você é, mas você não pode fazer isso). O que testar:
  • Requisição sem token algum → 401
  • Requisição com token expirado → 401
  • Requisição com token inválido ou forjado → 401
  • A resposta de erro não revela informações sobre tokens válidos

403 Forbidden

Autenticado, mas sem permissão. "Você está logado, mas não tem autorização para isso."

O que testar:
  • Usuário comum acessando endpoint de admin → 403
  • Usuário acessando dados privados de outro usuário → 403
  • A resposta não expõe nenhum dado que o usuário não deveria ver
Relevância para segurança: um check de 403 ausente significa que acesso não autorizado funciona, um bug de segurança real.

404 Not Found

O recurso solicitado não existe naquela URL.

O que testar:
  • Solicitar um recurso deletado → 404
  • Solicitar com um ID que nunca foi criado → 404
  • Para recursos sensíveis, não deve revelar se o recurso existe (contas de usuário: retornar 404 "user not found" vs 403 "forbidden" pode revelar a existência da conta)
  • É 404 ou 410? (410 = deletado permanentemente, algumas APIs fazem essa distinção)

405 Method Not Allowed

Você usou o método HTTP errado. GET em um endpoint que só aceita POST.

Relevância para testes: tente métodos errados intencionalmente. DELETE /users quando só deveria aceitar GET. Deve retornar 405, não 500 ou falha silenciosa.

409 Conflict

A requisição conflita com o estado atual do recurso.

Usos comuns:
  • Criar um usuário com e-mail que já existe
  • Editar um recurso que outra pessoa bloqueou
  • Conflito de versão (optimistic locking)
O que testar:
  • Criação duplicada → 409 (não 200 ou 500)
  • A resposta explica o conflito com clareza

422 Unprocessable Entity

O JSON da requisição é sintaticamente válido, mas semanticamente errado: a validação falhou.

Exemplo: corpo JSON válido, mas age: -5 viola a regra de que a idade deve ser positiva. 400 vs 422:
  • 400 = não consegue nem interpretar a requisição (JSON ruim, Content-Type errado)
  • 422 = interpretou, mas os valores falham na validação

Muitas APIs usam 400 para os dois casos. O que importa é consistência: escolha um e use corretamente em toda a API.

O que testar:
  • Cada campo obrigatório ausente → 422 com o nome do campo específico no erro
  • Valores fora do range válido → 422
  • Violações de regras de negócio → 422

429 Too Many Requests

Rate limiting: você enviou requisições demais em tempo curto demais.

O que testar:
  • Confirmar que headers de rate limit são retornados (X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After)
  • Após atingir o limite, requisições são rejeitadas
  • Após a janela expirar, requisições voltam a funcionar
Relevância para segurança: endpoints de login devem ter rate limiting para prevenir ataques de força bruta. Teste que 429 é retornado após X tentativas de login com falha.

5xx: códigos de erro do servidor

Esses são sempre bugs. A requisição era válida: o servidor falhou em processá-la.

500 Internal Server Error

Crash genérico do servidor. Algo inesperado aconteceu.

Em testes: se você consegue reproduzir um 500 de forma confiável, é um bug, mesmo que o input fosse intencionalmente inválido. Bom design de API significa que input inválido retorna 4xx, não 500. O que testar:
  • Input inválido nunca deve produzir 500: deve produzir 400/422
  • Campos opcionais nulos ou ausentes não devem produzir 500
  • Dados de edge case (arrays vazios, strings muito longas) não devem produzir 500

502 Bad Gateway

O servidor estava atuando como gateway/proxy e recebeu uma resposta ruim de um servidor upstream. Geralmente significa que uma dependência está fora.

503 Service Unavailable

O servidor está temporariamente indisponível: sobrecarregado ou em manutenção.

Relevância para testes: verifique como o frontend trata o 503. Mostra uma página de erro útil? Tenta novamente de forma inteligente? Degrada graciosamente?

504 Gateway Timeout

Similar ao 502: um gateway expirou aguardando por um servidor upstream. Aparece com frequência sob alta carga ou quando um serviço de terceiro está lento.

Tabela de referência rápida

| Código | Significado | Causa comum em bugs |

|--------|-------------|---------------------|

| 200 | OK | Retornado para criações que deveriam ser 201 |

| 201 | Created | Ausente: API retorna 200 para POST |

| 204 | No Content | Corpo retornado quando não deveria |

| 301 | Redirect Permanente | Tipo errado de redirect |

| 304 | Not Modified | Cache stale exibindo dados desatualizados |

| 400 | Bad Request | Retornado para input válido-mas-errado (deveria ser 422) |

| 401 | Unauthorized | Ausente: vulnerabilidade de bypass de autenticação |

| 403 | Forbidden | Ausente: vulnerabilidade de bypass de autorização |

| 404 | Not Found | 500 retornado para recursos ausentes |

| 409 | Conflict | Ausente: duplicatas criadas silenciosamente |

| 422 | Unprocessable Entity | Confundido com 400 |

| 429 | Too Many Requests | Ausente: força bruta possível |

| 500 | Internal Server Error | Disparado por input inválido (deveria ser 4xx) |

| 503 | Service Unavailable | Sem degradação graciosa no frontend |

Testando status codes com Playwright

test('criar usuário retorna 201', async ({ request }) => {
  const response = await request.post('/api/users', {
    data: { email: 'novo@teste.com', password: 'SenhaValida1' },
  });
  expect(response.status()).toBe(201);
});

test('e-mail duplicado retorna 409', async ({ request }) => {
  // Criar usuário primeiro
  await request.post('/api/users', {
    data: { email: 'existente@teste.com', password: 'SenhaValida1' },
  });
  // Tentar novamente com o mesmo e-mail
  const response = await request.post('/api/users', {
    data: { email: 'existente@teste.com', password: 'SenhaValida1' },
  });
  expect(response.status()).toBe(409);
});

test('token ausente retorna 401', async ({ request }) => {
  const response = await request.get('/api/profile');
  expect(response.status()).toBe(401);
});

test('perfil errado retorna 403', async ({ request }) => {
  // Usar token de membro, tentar acessar endpoint de admin
  const response = await request.get('/api/admin/users', {
    headers: { Authorization: `Bearer ${memberToken}` },
  });
  expect(response.status()).toBe(403);
});

Assertions de status code são os testes de API mais rápidos e confiáveis que você pode escrever. Rodam em milissegundos e capturam bugs de autorização, validação ausente e design incorreto de API.

→ Veja também: Testes de API 101: Tudo que Todo Engenheiro QA Precisa Saber em 2026 | O que é uma API REST? Um Guia Prático para Engenheiros QA | Testes de API com Playwright: Além da Interface | Autenticação em Testes de API: Chaves API, Tokens Bearer, OAuth2, JWT