Códigos HTTP com propósito

Cássio Scofield
5 min readJun 27, 2021

Um dos erros comuns que percebi em desenvolvedores menos experientes ao longo dos anos é o mal uso ou o não uso de códigos HTTP condizentes e específicos para tratar cada modo de falha. Não é tão incomum encontrar uma web-API que use apenas status 200 e 500 e isso trás sérios problemas para a manutenibilidade quando as aplicações começam a crescer.

Porque usar status-codes diferentes?

O primeiro e mais óbvio motivo do valor dos códigos refere-se a facilitar a vida do utilizador do endpoint, seja ele um desenvolvedor mobile ou front-end do mesmo time/empresa ou um desenvolvedor de uma empresa parceira/cliente que usa a sua API. O status-code escolhido corretamente ser um bom indicativo para o chamador do tipo de erro/problema que ele pode estar enfrentando. Se um desenvolvedor lê um status-code 400 já deveria saber (se não souber continua lendo que darei mais detalhes adiante) que está fazendo a chamada errada por exemplo.

O segundo motivo refere-se à troubleshooting, supondo que o app está se conectando à API e seu aplicativo já está em produção, missão cumprida? Nada disso, como todos já sabem por melhor que seja o seu código sempre surgem bugs. Os bugs ocorrem não apenas em código mal feitos, mas também em códigos que ficaram legados, por mudanças em regras de negócio, por mudanças em dependências… por melhor que fosse a sua v1.0.0, a manutenção e evolução do código sempre deixa brechas para problemas, que precisam ser encontrados. Os status-codes bem utilizados e mensagens de erro bem descritas são um primeiro sintoma lugar onde se deve olhar para se achar um problema.

O terceiro motivo é a evolução do segundo, para empresas que já estão mais maduras espera-se que a equipe técnica consiga perceber e corrigir problemas antes mesmo dos clientes ligarem reclamando. A diferenciação dos status-codes facilita o monitoramento e alarmística e, conseguinte, a rápida atuação da equipe técnica quando algo estranho é detectado.

Classes de status codes

Uma característica importante dos status-codes e erros TCP e HTTP é que eles são facilmente classificados a partir do range (prefixo):

0 — Erros de rede (TCP)

Em alguns frameworks vem como “undefined”, essa classe de erros significa que o seu cliente nem conseguiu chegar do outro lado.

O erro mais comum dessa classe é o ECONNREFUSED, geralmente acontece quando você se esqueceu de se conectar no wifi ou no proxy da sua empresa. Não vou entrar em muito detalhe sobre essa classe porque tecnicamente não é um status-code, mas se quiser saber mais detalhe segue o link: https://www.columbia.edu/sec/acis/db2/db2m0/db2tcp.htm

100 a 199 — Mensagens informativas

Essas mensagens são usadas pelo cliente para saber quando trocar de protocolo ou que a requisição foi recebida, mas ainda não foi processada, por exemplo.

200 a 299 — Mensagens afirmativas/positivas

Essas mensagens indicam que tudo ocorreu bem.

300 a 399 — Redirecionamento ou caching

Essas também são mensagens instrutivas, indicando ao browser onde ele deve buscar o conteúdo.

400 a 499 — Erro de cliente

Essas mensagens indicam que houve uma falha, provavelmente devido a um erro do usuário / chamador (front-end).

500 a 599 — Erro de servidor

Essas mensagens indicam que houve uma falha, provavelmente do lado do servidor (back-end ou banco de dados).

Status codes mais importantes

Agora que você já sabe identificar mais ou menos onde procurar um problema quando receber um status-code dependendo do prefixo, vamos detalhar os status-code que são mais usuais no dia-a-dia de um desenvolvedor, e que portanto você deve ter na ponta da lingua.

400 — Requisição inválida — Usuário não respeitou a interface do endpoint

Parâmetros não enviados ou enviados com formato inválido para o endpoint. Por exemplo: requisição deveria ter um query-string id_usuario, mas não passou ou requisição deveria passar uma data em formato YYYY-MM-DD, mas passou DD/MM/YY.

401 — Autenticação necessária / Não autorizado — Sessão inexistente, inválida ou expirada.

Por exemplo, usuário não fez login ou usuário enviou credenciais/token no campo errado, em formato inválido ou que já esteja expirado.

422 — Requisição não processável — Parâmetros estão válidos, mas não respeitam regra

Por exemplo, usuário no Android deseja baixar conteúdo disponível apenas no iOS ou usuário tenta aplicar cupom que já está expirado ou já foi usado por outro usuário.

404 — Recurso não foi encontrado — Indica que o usuário chamou a URL errada ou que o conteúdo não existe

Pode ser usado em busca por id (ex: GET /conteudo/123 > 404) para indicar que recurso não foi encontrado. Prefira não usar o 404 para indicar que o filtro passado não encontrou resultados, principalmente quando o resultado positivo for uma lista (ex: GET /usuarios?nome=Diogo > 200 [])

503 — Serviço indisponível — Geralmente ocorre quando há indisponibilidade de uma dependência externa à aplicação ou manutenção programada

Pode ser usado para indicar que o banco de dados fora do ar (Insert no MySQL não funcionou) ou quando uma API está indisponível (API de parceiro está retornando erro de rede por exemplo).

500 — Qualquer outro erro não previsto- inesperado, que não se encaixa em outro cenário

Geralmente usado quando nenhum outro código se adequa ou em caso de erro não previsto, por exemplo, crash da aplicação, exceção não tratada (catch global). Use esse código só em última instância ou nos seus ELSE.

Indo além dos códigos HTTP

As classes de código (4XX / 5XX) nos ajudam a ter um cheiro do problema, os status-codes no ajudam a identificar o erro, mas ainda precisamos de mais informações para entender como corrigí-lo. Para isso precisamos incrementar ainda mais o retorno HTTP, adicionando informações no body.

Um padrão bastante usado é o envio de 2 campos, um contendo um código detalhado e outro contendo uma mensagem legível. A mensagem pode ser apresentada diretamente para o usuário final ou o código pode ser usado para codificar uma mensagem específica no front-end sem gerar acoplamento e facilitar uma eventual internacionalização. Seguem alguns exemplos:

400 {
"codigo": "API_FATURAMENTO_PARAMETRO_CPF_OBRIGATORIO",
"mensagem": "O campo CPF é obrigatório"
}
401 {
"codigo": "API_FATURAMENTO_AUTENTICACAO_OBRIGATORIA",
"mensagem": "É necessário fazer login para continuar"
}
422 {
"codigo": "API_FATURAMENTO_CUPOM_USADO",
"mensagem": "Cupom já foi usado anteriormente"
}
503 {
"codigo": "API_FATURAMENTO_INDISPONIVEL",
"mensagem": "Não foi possível conectar com o sistema de pagamento"
}
500 {
"codigo": "API_FATURAMENTO_ERRO_INESPERADO",
"mensagem": "Erro inesperado na API de pagamentos"
}

Conclusão

Sempre que for usar um código de erro ou criar uma mensagem seja o mais específico possível, neste cenário tentar reaproveitar código existente ou fazer tratativas de erro genéricas demais pode ser um erro e que os seus colegas e até você mesmo do futuro vai ganhar um minuto hoje pra perder um dia daqui a pouco.

Referências:

Se você gostou deste conteúdo te indico um outro artigo que fiz a mais tempo também sobre web-apis: Más práticas em web-apis além de algumas referências externas que usei de base para este post.

Originally published at https://www.linkedin.com.

--

--

Cássio Scofield

Hi, I'm Cássio Scofield, full-stack mobile developer, currently working as technical leader at PEBMED (Whitebook Medical App)