Quando escrevemos APIs, há um ponto que sempre causa discórdia e discussão: qual http status code eu retorno para esta solicitação? Se você tem essa dúvida, parabéns! Você está a um passo de escrever melhores APIs. Agora, se você nunca sequer se preocupou com isso e retorna 200 – Ok para tudo, talvez seja o momento de você aprender a usar o http status code do jeito certo.
APIs, como discutimos antes, são interfaces públicas que permitem a integração entre sistemas. Para que essa integração seja saudável, é necessário que as duas partes dessa conversa falem a mesma língua, ou seja, o mesmo protocolo de comunicação. Alguns pontos – como a documentação, por exemplo – facilitam muito esse processo. Mas seguir o mínimo do protocolo ajuda muito, especialmente em cenários em que a documentação não está lá aquelas coisas. E parte importantíssima do protocolo HTTP é o Status Code retornado a cada requisição.
Mas o que é esse tal de HTTP Status Code?
Cada vez que você faz uma requisição, além do recurso esperado, o servidor anexa um valor numérico, na resposta, que representa do estado da mensagem – o tal do HTTP Status Code. Ele está dividido em algumas faixas numéricas:
- 1xx Informativo – utilizado durante as negociações entre cliente e servidor;
- 2xx Sucesso – Indica que a sua requisição foi bem sucedida;
- 3xx Redirecionamento – O cliente precisa fazer mais alguma coisa (provavelmente chamando outro endpoint) para concluir o processo;
- 4xx Erro no cliente – Algo está errado com a sua requisição;
- 5xx Erro no servidor – Algo está errado no servidor;
A maior parte dos frameworks possuem enums, constantes e outros statements de código que mapeiam os Status Codes. E como você pode perceber, apenas por essa classificação, os códigos ajudam na tomada de decisão, enriquecendo a resposta do servidor. Se você recebeu um retorno Http Status Code 201 - Created
, e o body
contém um objeto, é possível inferir que o objeto retornado é uma representação do recurso criado no servidor.
Más práticas com HTTPS Status Code
Como a própria classificação já é muito enriquecedora, algumas pessoas podem se sentir tentadas a fazer uso apenas do primeiro número. Nesse caso, toda requisição ou retorna 200 - Ok
ou 404 - Not Found
. E claro, as exceções são mapeadas para o erro 500 - Internal Server Error
. E sim, mesmo sendo esses os Status Codes mais conhecidos, eles sozinhos não dizem muita coisa. Por exemplo: Se eu não estou autorizado a acessar um recurso, eu deveria receber um retorno 404 - Not Found
? Mas o recurso existe no final das contas, eu só não tenho permissão para utilizá-lo. Ou ainda: Se está tudo certo com a minha requisição, mas uma regra de negócio foi infringida, eu deveria retornar um status code 400 - Bad Request
?
Essas questões, por si só, já são polêmicas. E mesmo em ambiente em que já existe uma certa maturidade na construção de APIs, as confusões existem. Por isso é importantíssimo a gente documentar bem as nossas APIs. Por outro lado, o extremo da má prática é o famoso: 200 - Ok
Body: { "error": true}
.
Alguém até pode argumentar “Mas a conexão foi bem sucedida, é que aconteceu algum erro no processamento”. Bom, primeiro que se a conexão não pudesse ser resolvida, algum outro erro aconteceria no processo: um erro de I/O ou até mesmo de Time out. Quando você adota essa má prática, um panda morre na china, você torna o seu sistema menos “integrável”, afinal, o mundo inteiro entende que “se o retorno foi 200 - ok
, tá tudo certo na requisição”. Quando não foi isso o que realmente aconteceu. Ou seja: Alguém está mentindo.
É óbvio que você pode proceder como quiser com as suas APIs, adotando e definindo os seus próprio maneirismos e variações do protocolo. Minha intenção não é forçar regras e apontar para os seus erros. Meu maior ganho com essa discussão é introduzir você no mundo das especificações e RFCs que fazem o mundo falar a mesma língua. E quando falamos a mesma língua, a comunicação flui melhor. Concorda?
Boas práticas no uso de HTTP Status Code
1. Conheça as variações de HTTP Status Code
A primeira coisa que você precisa fazer é conhecer todas as variações de HTTP Status Codes. Aqueles sites de gatinhos são legais, mas adicionam pouco conhecimento prático. Por isso eu indico pra você o ótimo site da Mozilla (https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status) e também o HTTP Status (https://www.httpstatus.com.br/) que além da descrição do que é esperado no retorno, também inclui a RFC que o define. Vale muito a pena conferir
2. Apresente para o seu time
Por mais simples e óbvio que possa parecer esse tipo de conhecimento, é importante que todo o time esteja na mesma página. Por isso, não deixe de compartilhar a fonte de conhecimento com as pessoas que estão ao seu lado no trabalho.
3. Defina um padrão
Sim, é isso mesmo. Defina o seu próprio padrão, mesmo que já existam as RFCs. Ao se deparar com esse conteúdo, você pode sentir a tenção de aplicar todos os Status Codes no seu código. No entanto, esse esforço pode ser tão grande e o seu time estar em um nível de maturidade que esse nível de detalhamento traria mais confusão.
4. Publique o seu padrão
Pessoas na área de tecnologia vem e vão. É preciso ter documentada as decisões que você, ao lado do seu time, tomaram. Portanto, publique o seu padrão. Não estou falando de publicar a API, mas sim dizer quais as regras e valores orientam a tomada de decisão. E principalmente, mantenha essa documentação atualizada. Se encontrou um caso não mapeado, adicione na sua documentação. Se fizer isso, vai me agradecer mais tarde.
Com quais Status Code começar?
Como toda lista opinativa, alguém pode discordar de mim. E tudo bem. O importante é que, no final das contas, você tome a sua decisão junto com seu time. Vamos à lista:
200 - Ok
: Para todas as requisições que cumpriram o seu intento. Se você requisitou um recurso e ele existe, retorne 200 - Ok
. Se você fez uma pesquisa, e a pesquisa retornou vazio, também retorne 200 - Ok
. Afinal, sua requisição está perfeita. Apenas não retornou dados para mostrar.
201 - Created
: Sempre que você criar um novo recurso, retorne esse status code. Você pode retornar um body com a representação do recurso criado, ou simplesmente retornar o endereço onde ele estará disponível no header location
.
202 - Accepted
: Para processamento assíncrono. Um exemplo clássico é quando você pede pra criar um relatório e depois recebe ele por e-mail. A aplicação retornou imediatamente, mas houve um processamento em paralelo.
204 - No Content
: Quando a sua requisição não retorna conteúdo. No caso de utilizar um verbo DELETE
na sua requição, por exemplo. E 204 - No Content
é sem conteúdo MESMO, ou seja, utilize esse HTTP Status apenas quando aquela requisição NUNCA irá retornar qualquer valor.
400 - Bad Request
: Todo mundo erra, não é mesmo? Até o cliente pode errar. Nesses casos, retorne Bad request
. Para o caso de ser ferida uma regra de negócio, uma opção é retornar 422 - Unprocessable Entity
(ou o 409 - Conflict
), para quando você está tentando incluir um registro duplicado, por exemplo. Mas o Bad Request
também serve para esses casos. Esse tipo de retorno espera um objeto que seja capaz de descrever o erro. Vamos falar dessa implementação em outro momento.
401 - Unauthorized
: Se você confunde esse retorno com o 403
, bem vindo ao clube! Confesso que grande parte das vezes recorro a documentação pra lembrar quem é o quê. Uma dica pra você tentar decorar é: “Sem autorização”, quer dizer que eu ainda preciso de autorização. Já o…
403 - Forbiden
: Este está dizendo que: “ok, eu sei quem você é e estou vendo aqui na sua credencial que você está proibido de acessar esse recurso”.
404 - Not Found
: Não utilize este status code quando um filtro de pesquisa não encontrar valor. O 404
diz que aquele recurso, aquela URL não existe. E isso é muito diferente de uma query que não encontrou valores. A URL está correta; a filtragem é que foi excessivamente refinada. Então, utilize o 404
apenas quando o recurso realmente não existir.
500 - Internal Server Error
: Para exceções não tratadas. Existem outras possibilidades de retorno, mas essas, em geral, o próprio ambiente as dispara pra você.
Finalizando…
Alguns lugares em que trabalhei, essa lista era ainda menor (excluindo o 204, por exemplo) ou sequer havia um padrão. Como eu já disse, algumas interpretações podem criar dúvidas e gerar discussões. Isso é saudável! É importantíssimo fomentar discussões técnicas dentro do time – quer sejam avançadas ou não.
Há quem diga, por exemplo, que uma chamada DELETE deveria retornar 200 - Ok
não importando a quantidade de vezes que a requisição seja feita para o mesmo recurso. Outras pessoas poderiam argumentar que, na segunda requisição, o retorno deveria ser 404 - Not Found
ou ainda 410 - Gone
, afinal o recurso já não existe mais. No caso de uma sobreposição de chaves únicas, já vi a defesa do uso do 409 - Conflict
para dar ao cliente a chance de implementar um reconcile error pattern, alterando as informações conflitantes. Outras pessoas que o correto seria o 422 - Unprocessable Entity
.
Quando chegarem a um consenso, é o momento de documentá-lo. Mas especialmente, também documentar a sua API, facilitando a vida de quem irá consumir as suas funcionalidade.
E é sobre documentação de APIs que falaremos nos próximos artigos!