DEV Community

Vinícius Carregosa
Vinícius Carregosa

Posted on

HTTP Status Codes: semântica e comunicação entre cliente e servidor

Em uma comunicação HTTP, não basta que o servidor receba uma requisição e envie uma resposta. É necessário que exista uma maneira padronizada de comunicar o resultado daquela operação.

Imagine uma aplicação que solicita os dados de um usuário a uma API. O recurso pode existir, não ser encontrado, exigir autenticação ou até mesmo não estar disponível devido a uma falha interna. Cada uma dessas situações representa um resultado diferente e precisa ser comunicado adequadamente ao cliente.

É nesse contexto que surgem os HTTP Status Codes, ou códigos de status HTTP.

Eles são códigos numéricos de três dígitos presentes na linha de status de uma resposta HTTP. Sua finalidade é indicar o resultado do processamento de uma requisição, permitindo que clientes, servidores, intermediários e outras aplicações interpretem a resposta de maneira padronizada.

Mais do que indicar sucesso ou falha, os códigos de status fazem parte da semântica do protocolo HTTP e estabelecem um contrato de comunicação entre as aplicações.

1. Como funcionam os códigos de status HTTP?

Toda resposta HTTP possui uma linha de status, que contém a versão do protocolo, o código numérico e uma descrição textual.

Observe o exemplo:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 42,
    "name": "Vinicius"
}
Enter fullscreen mode Exit fullscreen mode

Nesse caso:

  • HTTP/1.1 representa a versão do protocolo;
  • 200 é o código de status;
  • OK é a descrição textual associada ao código.

A descrição textual é conhecida como reason phrase. Ela possui caráter informativo, enquanto o código numérico é o elemento utilizado para identificar semanticamente o resultado da resposta.

O cliente não precisa interpretar a descrição textual para compreender o resultado da operação. O código numérico já fornece essa informação de maneira padronizada.

Por exemplo, ao solicitar um usuário inexistente, o servidor pode responder:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
    "message": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

Nos dois exemplos, a comunicação HTTP aconteceu normalmente. O que mudou foi o resultado da operação solicitada.

Essa distinção é fundamental: uma resposta HTTP pode ser entregue corretamente mesmo quando a operação solicitada não alcança o resultado esperado.

2. As cinco categorias de códigos HTTP

Os códigos de status são organizados em cinco categorias, determinadas pelo primeiro dígito do código.

Categoria Significado Descrição
1xx Informational Indica que a requisição foi recebida e que o processamento continua.
2xx Success Indica que a requisição foi recebida, compreendida e processada com sucesso.
3xx Redirection Indica que é necessária uma ação adicional para concluir a requisição, geralmente envolvendo redirecionamento.
4xx Client Error Indica um problema relacionado à requisição enviada pelo cliente.
5xx Server Error Indica que o servidor não conseguiu concluir uma requisição aparentemente válida.

Essa classificação permite identificar rapidamente a natureza de uma resposta sem precisar conhecer previamente cada código individual.

É importante compreender que a categoria representa uma classificação semântica, não necessariamente a causa técnica exata do problema.

Um 500 Internal Server Error, por exemplo, informa que ocorreu uma falha interna no servidor, mas não revela se ela foi causada por uma exceção não tratada, uma dependência indisponível ou outro problema.

3. Códigos informacionais (1xx)

Os códigos da categoria 1xx representam respostas informacionais. Eles indicam que a requisição foi recebida e que o processamento continua.

Não representam necessariamente a conclusão da operação solicitada.

Um exemplo é o 100 Continue, utilizado em situações nas quais o cliente envia inicialmente os cabeçalhos de uma requisição e aguarda uma confirmação antes de transmitir o corpo.

Isso pode ser útil em requisições que envolvem grandes volumes de dados, permitindo que o cliente saiba se deve continuar com o envio.

Outro exemplo é o 101 Switching Protocols, utilizado quando ocorre uma mudança de protocolo, como no estabelecimento de determinadas conexões WebSocket.

Embora importantes para o funcionamento do protocolo, esses códigos geralmente não aparecem com frequência no desenvolvimento cotidiano de endpoints REST.

4. Códigos de sucesso (2xx)

Os códigos da categoria 2xx indicam que a requisição foi processada com sucesso.

Entretanto, nem todos representam exatamente o mesmo resultado.

200 OK

Indica que a requisição foi processada com sucesso.

É bastante utilizado em operações de consulta e também pode aparecer em operações de atualização.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 42,
    "name": "Vinicius"
}
Enter fullscreen mode Exit fullscreen mode

201 Created

Indica que a requisição foi processada com sucesso e resultou na criação de um novo recurso.

É especialmente utilizado em operações POST.

HTTP/1.1 201 Created
Location: /users/43
Content-Type: application/json

{
    "id": 43,
    "name": "Maria"
}
Enter fullscreen mode Exit fullscreen mode

O cabeçalho Location pode indicar o endereço do recurso recém-criado.

202 Accepted

Indica que a requisição foi aceita para processamento, mas que esse processamento ainda não foi concluído.

É especialmente útil em operações assíncronas.

Imagine uma API que recebe uma solicitação para gerar um relatório extenso. Em vez de manter a conexão aberta até terminar todo o processamento, o servidor pode aceitar a solicitação e executá-la posteriormente.

HTTP/1.1 202 Accepted
Content-Type: application/json

{
    "message": "Report generation accepted",
    "jobId": "12345"
}
Enter fullscreen mode Exit fullscreen mode

O cliente recebe a confirmação de que a solicitação foi aceita, mas isso não significa que o relatório já esteja pronto.

204 No Content

Indica que a requisição foi processada com sucesso, mas não existe conteúdo a ser enviado no corpo da resposta.

É comum em operações de exclusão e atualização que não precisam retornar dados.

HTTP/1.1 204 No Content
Enter fullscreen mode Exit fullscreen mode

Uma característica importante é que uma resposta 204 não deve conter corpo de mensagem.

Uma distinção importante

Considere quatro situações:

Situação Status Interpretação
Usuário consultado com sucesso 200 O recurso foi encontrado e seus dados foram retornados.
Usuário criado com sucesso 201 Um novo recurso foi criado.
Relatório solicitado para processamento 202 A solicitação foi aceita, mas ainda está sendo processada.
Usuário excluído sem retorno de dados 204 A operação foi concluída sem conteúdo na resposta.

Perceba que todos representam sucesso, mas comunicam resultados diferentes.

Essa distinção é importante porque os códigos HTTP não são apenas indicadores de que algo deu certo ou errado. Eles fazem parte do contrato de comunicação de uma API.

5. Códigos de redirecionamento (3xx)

Os códigos da categoria 3xx indicam que o cliente precisa realizar alguma ação adicional para concluir a requisição.

O cenário mais conhecido envolve redirecionamentos, nos quais o servidor informa que determinado recurso está disponível em outro endereço.

Entre os principais códigos estão:

301 Moved Permanently

Indica que o recurso foi movido permanentemente para outra localização.

O servidor geralmente informa o novo endereço por meio do cabeçalho Location.

302 Found

Indica que o recurso está temporariamente disponível em outra localização.

Diferentemente do 301, o redirecionamento não representa uma mudança permanente.

304 Not Modified

Indica que o recurso não foi modificado desde a última versão conhecida pelo cliente.

É utilizado em mecanismos de cache HTTP, permitindo evitar o envio desnecessário de uma representação que o cliente já possui.

Por exemplo, uma aplicação pode realizar uma requisição condicional utilizando o cabeçalho If-None-Match. Caso a representação continue válida, o servidor pode responder com 304, sem reenviar o conteúdo.

É importante observar que nem todo código 3xx representa necessariamente um redirecionamento para outra URL. O 304, por exemplo, está relacionado à validação de cache.

6. Códigos de erro do cliente (4xx)

Os códigos da categoria 4xx indicam que existe algum problema relacionado à requisição enviada pelo cliente.

Isso não significa necessariamente que o usuário cometeu um erro. O problema pode estar na estrutura da requisição, nas credenciais utilizadas, nas permissões disponíveis ou nas condições exigidas pela aplicação.

Essa categoria merece atenção especial no desenvolvimento de APIs, pois escolhas inadequadas podem dificultar a interpretação dos erros pelos consumidores.

400 Bad Request

Indica que o servidor não conseguiu processar a requisição devido a um problema relacionado à sua estrutura ou aos dados enviados.

Um exemplo seria uma requisição com JSON malformado:

POST /users HTTP/1.1
Content-Type: application/json

{
    "name": "Maria",
    "age":
}
Enter fullscreen mode Exit fullscreen mode

O corpo enviado não representa um JSON válido, impossibilitando sua interpretação adequada.

401 Unauthorized

Indica que a requisição não possui credenciais de autenticação válidas para acessar o recurso.

Apesar do nome, esse código está relacionado à autenticação, não à autorização.

Imagine uma API que exige um token de acesso. Se o cliente não enviar o token ou utilizar um token inválido, o servidor poderá responder com 401.

403 Forbidden

Indica que o servidor compreendeu a requisição, mas se recusa a atendê-la.

É frequentemente utilizado quando o cliente está autenticado, mas não possui as permissões necessárias para executar determinada operação.

Imagine um sistema que possui três perfis:

  • Administrador;
  • Operador;
  • Visualizador.

Se um usuário com perfil de visualizador tentar excluir um registro, a aplicação poderá responder com 403, pois ele não possui autorização para realizar essa operação.

401 versus 403: qual a diferença?

Essa é uma das distinções mais importantes entre os códigos HTTP.

Código Contexto Significado
401 Falha de autenticação O cliente precisa apresentar credenciais válidas.
403 Falha de autorização O acesso foi recusado por falta de permissão.

Em termos simples, autenticação está relacionada à identificação de quem está realizando a requisição, enquanto autorização determina o que essa identidade pode fazer.

404 Not Found

Indica que o servidor não encontrou uma representação atual do recurso solicitado ou não deseja revelar sua existência.

É bastante utilizado quando uma aplicação tenta consultar um registro inexistente.

GET /users/999 HTTP/1.1
Enter fullscreen mode Exit fullscreen mode

Resposta:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
    "message": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

O código também pode ser utilizado por razões de segurança, quando a aplicação não deseja revelar se determinado recurso existe.

405 Method Not Allowed

Indica que o método HTTP utilizado não é permitido para o recurso solicitado.

Imagine um endpoint que disponibiliza apenas operações de consulta:

POST /users/42 HTTP/1.1
Enter fullscreen mode Exit fullscreen mode

Se o recurso não permitir POST, o servidor poderá responder com 405.

Nesse caso, o cabeçalho Allow pode informar os métodos suportados:

HTTP/1.1 405 Method Not Allowed
Allow: GET
Enter fullscreen mode Exit fullscreen mode

409 Conflict

Indica que a requisição não pôde ser concluída devido a um conflito com o estado atual do recurso.

Imagine uma aplicação que não permite cadastrar dois usuários com o mesmo endereço de e-mail.

Se um cliente tentar cadastrar um e-mail que já está associado a outro usuário, a aplicação poderá retornar 409.

HTTP/1.1 409 Conflict
Content-Type: application/json

{
    "message": "Email already registered"
}
Enter fullscreen mode Exit fullscreen mode

Esse código também pode ser utilizado em situações envolvendo conflitos de versão ou alterações incompatíveis com o estado atual de um recurso.

422 Unprocessable Content

Indica que o servidor compreendeu o tipo de conteúdo enviado e conseguiu interpretar sua estrutura, mas não conseguiu processar as instruções devido a problemas semânticos.

Imagine uma requisição com JSON perfeitamente válido:

{
    "name": "",
    "age": -5
}
Enter fullscreen mode Exit fullscreen mode

Embora o conteúdo seja um JSON válido, os valores enviados não atendem às regras de validação da aplicação.

Nesse cenário, uma resposta 422 pode ser adequada.

400 versus 422

A distinção depende da natureza do problema:

  • 400: a requisição apresenta um problema que impede seu processamento adequado, como uma estrutura inválida.
  • 422: o conteúdo foi compreendido, mas não atende às condições semânticas necessárias para executar a operação.

É importante destacar que algumas APIs utilizam 400 também para erros de validação. A escolha deve considerar a semântica HTTP e manter consistência no contrato da aplicação.

7. Códigos de erro do servidor (5xx)

Os códigos da categoria 5xx indicam que o servidor não conseguiu concluir uma requisição aparentemente válida.

Diferentemente dos códigos 4xx, que estão relacionados a problemas na requisição do cliente, os códigos 5xx representam falhas durante o processamento ou na comunicação com componentes necessários para atender à solicitação.

500 Internal Server Error

É um código genérico utilizado quando ocorre uma condição inesperada que impede o servidor de concluir a requisição.

Um exemplo seria uma exceção não tratada durante a execução de uma operação no backend.

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
    "message": "An unexpected error occurred"
}
Enter fullscreen mode Exit fullscreen mode

É importante que detalhes internos da aplicação, como stack traces, caminhos de arquivos e informações sensíveis, não sejam expostos diretamente ao cliente.

Essas informações devem ser registradas em mecanismos apropriados de observabilidade e monitoramento.

502 Bad Gateway

Indica que um servidor atuando como gateway ou proxy recebeu uma resposta inválida de um servidor upstream.

Imagine uma arquitetura na qual uma requisição passa por um API Gateway antes de chegar ao serviço responsável pelo processamento.

Se o gateway receber uma resposta inválida desse serviço, poderá retornar 502 ao cliente.

503 Service Unavailable

Indica que o servidor está temporariamente incapaz de atender à requisição.

Isso pode acontecer devido a manutenção, sobrecarga ou indisponibilidade temporária de algum componente necessário.

O servidor pode utilizar o cabeçalho Retry-After para informar quando o cliente poderá tentar novamente.

504 Gateway Timeout

Indica que um servidor atuando como gateway ou proxy não recebeu uma resposta dentro do tempo esperado de um servidor upstream.

Imagine que uma aplicação depende de outro serviço para concluir determinada operação. Se esse serviço demorar além do limite de espera configurado, o gateway poderá retornar 504.

502, 503 e 504: entendendo as diferenças

Código Significado Exemplo
502 Resposta inválida do servidor upstream. O gateway recebe uma resposta inválida de um serviço.
503 Serviço temporariamente indisponível. O serviço está em manutenção ou sobrecarregado.
504 Tempo de espera excedido. O serviço upstream não responde dentro do prazo esperado.

Esses códigos são especialmente relevantes em arquiteturas distribuídas, nas quais uma requisição pode atravessar diferentes serviços, proxies e gateways antes de chegar ao seu destino.

8. A importância da escolha correta dos códigos HTTP

A escolha de um código de status não deve ser tratada como um detalhe secundário da implementação.

Em uma API, os códigos HTTP fazem parte do contrato consumido por outras aplicações. Portanto, uma resposta semanticamente inadequada pode gerar interpretações incorretas e comportamentos inesperados nos clientes.

Imagine uma API que retorna 200 OK para todas as situações, inclusive quando ocorre uma falha durante o processamento.

Embora o corpo da resposta possa conter uma mensagem informando o erro, o código HTTP comunica que a requisição foi processada com sucesso.

Isso pode prejudicar:

  • O tratamento de erros no frontend;
  • A implementação de mecanismos de retentativa;
  • O monitoramento e a observabilidade;
  • A integração com outros serviços;
  • A interpretação automatizada das respostas.

Uma aplicação cliente pode, por exemplo, utilizar o status HTTP para decidir se deve apresentar uma mensagem ao usuário, solicitar autenticação novamente ou tentar executar a operação em outro momento.

Por isso, a escolha correta dos códigos contribui diretamente para a previsibilidade e a interoperabilidade das APIs.

9. Considerações sobre retentativas e operações idempotentes

Outro aspecto importante é a relação entre códigos HTTP, retentativas e idempotência.

Em sistemas distribuídos, falhas de comunicação são situações possíveis. Uma requisição pode não receber resposta dentro do tempo esperado, mesmo que o servidor tenha executado a operação.

Imagine um cliente que envia uma solicitação para criar um pedido. O servidor processa a operação, mas a conexão é interrompida antes que a resposta chegue ao cliente.

Sem receber a confirmação, o cliente pode tentar novamente. Dependendo da implementação, isso pode resultar na criação de dois pedidos.

É nesse contexto que a idempotência ganha importância.

Uma operação é considerada idempotente quando sua execução repetida produz o mesmo efeito pretendido no estado do servidor que uma única execução.

O método PUT, por exemplo, é definido como idempotente pelo HTTP. Já o POST não possui essa garantia por padrão.

Mecanismos como chaves de idempotência podem ser utilizados em APIs para evitar que retentativas provoquem operações duplicadas.

Além disso, códigos como 503 podem indicar uma indisponibilidade temporária, mas isso não significa que toda resposta de erro deva provocar uma nova tentativa automaticamente.

A política de retentativas deve considerar a natureza da falha, o método HTTP, a possibilidade de duplicação e o comportamento do serviço.

10. Padronização das respostas de erro

Além de escolher corretamente o código HTTP, é importante manter um padrão para o corpo das respostas de erro.

Imagine uma API que retorna mensagens diferentes para cada endpoint, utilizando estruturas incompatíveis entre si.

Isso obriga os clientes a implementar tratamentos específicos para cada situação, aumentando a complexidade da integração.

Uma alternativa é adotar uma estrutura padronizada para os erros.

Um exemplo seria:

{
    "type": "https://api.exemplo.com/errors/validation",
    "title": "Validation Error",
    "status": 422,
    "detail": "The request contains invalid data.",
    "instance": "/users",
    "errors": [
        {
            "field": "email",
            "message": "Invalid email address"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Uma referência importante para esse tipo de padronização é o Problem Details for HTTP APIs, definido pela RFC 9457.

Ele estabelece um formato padronizado para representar informações sobre problemas em respostas HTTP.

A adoção desse padrão facilita a interpretação dos erros, melhora a consistência das APIs e reduz a necessidade de tratamentos específicos em cada cliente.


Conclusão

Os códigos de status HTTP são parte fundamental da comunicação entre aplicações. Eles permitem que clientes e servidores compartilhem uma interpretação padronizada sobre o resultado das operações realizadas.

Compreender suas categorias e diferenças vai além de memorizar códigos. É necessário entender a semântica de cada resposta e saber aplicá-la de acordo com o contexto da operação.

Em arquiteturas modernas, especialmente aquelas baseadas em APIs REST e microsserviços, essa responsabilidade ganha ainda mais importância. Uma requisição pode atravessar diferentes componentes, e cada resposta precisa comunicar corretamente o que aconteceu durante o processamento.

Uma API bem projetada não se preocupa apenas em executar operações, mas também em comunicar seus resultados de maneira clara, consistente e previsível.

Afinal, uma boa comunicação entre sistemas começa pela capacidade de cada componente compreender não apenas o que foi solicitado, mas também o resultado daquilo que foi executado.

Referências

Top comments (0)