Códigos de status HTTP REST por falha na validação ou duplicação inválida

826

Estou criando um aplicativo com uma API baseada em REST e cheguei ao ponto de especificar códigos de status para cada solicitação.

Qual código de status devo enviar para solicitações com falha na validação ou onde uma solicitação está tentando adicionar uma duplicata no meu banco de dados?

Examinei http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html, mas nenhum deles parece correto.

Existe uma prática comum ao enviar códigos de status?

alexn
fonte
14
Abra httpstatus.es , clique com o botão direito >> Guia Pin: P
Salman von Abbas

Respostas:

780

Para falha na validação de entrada: 400 Solicitação incorreta + sua descrição opcional. Isso é sugerido no livro " RESTful Web Services ". Para envio duplo: 409 Conflito


Atualização junho de 2014

A especificação relevante costumava ser RFC2616 , que dava o uso de 400 (Bad Request) de maneira bastante restrita como

A solicitação não pôde ser entendida pelo servidor devido à sintaxe incorreta

Portanto, poderia ter sido argumentado que era inapropriado para erros semânticos. Mas não mais; desde junho de 2014, a norma relevante RFC 7231 , que substitui a anterior RFC2616, fornece o uso de 400 (Bad Request) de maneira mais ampla

o servidor não pode ou não processará a solicitação devido a algo que é considerado um erro do cliente

Deamon
fonte
3
Sim, o corpo da solicitação faz parte da sintaxe.
deamon
62
Solicitação incorreta é definitivamente a resposta mais comum a esse tipo de problema. A única outra alternativa é 422 entidade não processável. Na verdade, ele vem do WebDav, mas é perfeitamente válido reutilizar qualquer código de status que tenha sido registrado na IANA.
Darrel Miller
19
Então, como você diferencia entre dados malformados que o servidor não pode nem analisar e um erro de validação? Um cliente lidaria com essas duas respostas de maneira completamente diferente. Para validação, eles provavelmente exibem os erros para o usuário. Para dados verdadeiramente "malformados", eles registrariam o erro para que o erro no método que gera a solicitação pudesse ser corrigido.
Josh Noe
18
Não concordo com a sua interpretação da RFC7231, embora afirme que something perceived to be a client errortodos os exemplos dados neste parágrafo são violações do protocolo HTTP, não erros lógicos: sintaxe, enquadramento, roteamento. Portanto, considero que a especificação HTTP não permite 400 para falha na validação no nível do aplicativo.
Dima Tisnek 23/09
2
por que não usar uma entidade 422 - Unprocessable? Parece mais lógico para mim
java_geek 7/07
278
  • Falha na validação: 403 Proibido ("O servidor entendeu a solicitação, mas está se recusando a atendê-la"). Ao contrário da opinião popular, o RFC2616 não diz que "403 é destinado apenas à autenticação com falha", mas "403: Eu sei o que você deseja, mas não o faço". Essa condição pode ou não ser devido à autenticação.
  • Tentando adicionar uma duplicata: 409 Conflito ("A solicitação não pôde ser concluída devido a um conflito com o estado atual do recurso.")

Você definitivamente deve dar uma explicação mais detalhada nos cabeçalhos de resposta e / ou no corpo (por exemplo, com um cabeçalho personalizado - X-Status-Reason: Validation failed).

Piskvor saiu do prédio
fonte
17
@ Deamon: Essa não é a especificação, é a Wikipedia, ou seja, a opinião de alguém sobre "o que códigos de status HTTP significam"; observe que a página diz essencialmente "é isso que Apache significa com 403, é isso que IIS significa com 403" e em nenhum lugar faz referência à RFC oficial. Você parece estar repetindo "403 significa o que quer que o Apache diga". NÃO. O RFC real (que é o documento relevante, não a implementação do Apache, nem a implementação do IIS, nem a implementação de mais ninguém) está aqui: w3.org/Protocols/rfc2616/rfc2616-sec10.html
Piskvor deixou o prédio em
57
"10.4.4 403 Proibido O servidor entendeu a solicitação, mas está se recusando a atendê-la. A autorização não ajudará e a solicitação NÃO DEVE ser repetida. Se o método da solicitação não foi HEAD e o servidor desejar tornar público o motivo da solicitação não for cumprida, DEVE descrever o motivo da recusa na entidade. Se o servidor não desejar disponibilizar essas informações ao cliente, o código de status 404 (Não encontrado) poderá ser utilizado. " Não vejo ênfase aqui ("DEVERIA / DEVE NÃO" serem palavras-chave da RFC 2119, não de ênfase); essa é a sua ideia do que "proibido" significa, não da RFC.
Piskvor saiu do prédio
10
Eu gosto desta resposta, mas ainda vejo um pequeno problema. De acordo com as especificações , quando um 403 é retornado, "a solicitação NÃO DEVE ser repetida". No entanto, retornar um 409 "é permitido apenas em situações em que se espera que o usuário consiga resolver o conflito e reenviar a solicitação". No caso de uma duplicata, acho que 403 é mais apropriado, pois você não pode realmente resolver o conflito (exceto excluindo a instância anterior do recurso).
Pablobm
2
Para a própria mensagem de erro, você deve modificar a frase do motivo, portanto, enviar o cabeçalho HTTP/1.0 403 Form validation errorsé o caminho mais limpo a seguir.
aleemb
6
IMO, 422 "Entidade não processável" faz muito mais sentido. Meu raciocínio é que não é que o servidor se recuse a atender à solicitação, é que o servidor não pode atender à solicitação.
tybro0103
225

Eu recomendo o código de status 422, "Entidade não processável" .

11.2 422 Entidade não processável

O código de status 422 (Entidade não processável) significa que o servidor entende o tipo de conteúdo da entidade de solicitação (portanto, um código de status 415 (Tipo de mídia não suportado) é inapropriado) e a sintaxe da entidade de solicitação está correta (portanto, 400 (Solicitação incorreta) ) código de status é inadequado), mas não conseguiu processar as instruções contidas. Por exemplo, essa condição de erro pode ocorrer se um corpo de solicitação XML contiver instruções XML bem formadas (ou seja, sintaticamente corretas), mas semanticamente erradas.

Julian Reschke
fonte
11
Claro que é um código de status HTTP, consulte iana.org/assignments/http-status-codes . Há mais códigos de status do que os definidos no RFC 2616.
Julian Reschke
7
WebDAV é uma extensão HTTP . "Extensões HTTP para criação e versão distribuída na Web (WebDAV)" Portanto, o código de status 422 não é um código de status http, mas um código de status de uma extensão de http.
deamon
16
Deamon, isso não faz sentido. O HTTP define como definir novos códigos, e é isso que o WebDAV está fazendo. Há um registro de código de status por um motivo.
Julian Reschke
14
FYI - Descrição RFC de 422: 11.2. 422 Entidade não processável O código de status 422 (Entidade não processável) significa que o servidor entende o tipo de conteúdo da entidade solicitada (portanto, um código de status 415 (Tipo de mídia não suportado) é inapropriado) e a sintaxe da entidade solicitada está correta (portanto, 400 O código de status (solicitação incorreta) é inadequado), mas não conseguiu processar as instruções contidas. Por exemplo, essa condição de erro pode ocorrer se um corpo de solicitação XML contiver instruções XML bem formadas (ou seja, sintaticamente corretas), mas semanticamente erradas.
Steve Kallestad
6
E os tópicos não 'expiram'. Eles precisam ser mantidos vivos ou os principais resultados de pesquisa do Google começam a se tornar imprecisos.
precisa
81

200,300, 400, 500 são todos muito genéricos. Se você quiser genérico, 400 está OK.

422 é usado por um número crescente de APIs e é usado até mesmo pelo Rails imediatamente.

Independentemente do código de status que você escolher para sua API, alguém discordará. Mas eu prefiro 422 porque penso em '400 + status de texto' como muito genérico. Além disso, você não está aproveitando um analisador pronto para JSON; por outro lado, um 422 com uma resposta JSON é muito explícito e muitas informações de erro podem ser transmitidas.

Falando em resposta JSON, costumo padronizar a resposta de erro do Rails para este caso, que é:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

Esse formato é perfeito para validação de formulários, que considero o caso mais complexo para suporte em termos de "riqueza de relatórios de erros". Se a sua estrutura de erros for essa, provavelmente ela atenderá a todas as suas necessidades de relatório de erros.

sethcall
fonte
2
E os erros decorrentes de interações entre os argumentos. Ou seja, arg1é válido e arg2é válido, mas a combinação dos dois, com os valores específicos enviados, não é válida.
Jonah #
1
Eu não pensaria demais; basta escolher uma que pareça possuir o relacionamento.
sethcall
ou mesmo apenas erro nos dois argumentos. Como usuário, acho que gostaria de ver o erro em cada um dos campos conflitantes, eu acho.
snuggles
Agradável!. explícita é melhor do que implícito
bhathiya-perera
46

200

Ugh ... (309, 400, 403, 409, 415, 422) ... muitas respostas tentando adivinhar, argumentar e padronizar qual é o melhor código de retorno para uma solicitação HTTP bem - sucedida, mas uma falha na chamada REST .

É errado misturar códigos de status HTTP e códigos de status REST.

No entanto, vi muitas implementações misturando-as e muitos desenvolvedores podem não concordar comigo.

Os códigos de retorno HTTP estão relacionados a HTTP Requestele próprio. Uma chamada REST é feita usando uma solicitação do Hypertext Transfer Protocol e funciona em um nível mais baixo do que o próprio método REST invocado. REST é um conceito / abordagem e sua saída é um resultado comercial / lógico , enquanto o código de resultado HTTP é um transporte .

Por exemplo, retornar "404 Não encontrado" quando você chama / users / é confuso, porque pode significar:

  • O URI está errado (HTTP)
  • Nenhum usuário encontrado (REST)

"403 Proibido / Acesso Negado" pode significar:

  • É necessária permissão especial. Os navegadores podem lidar com isso perguntando ao usuário / senha. (HTTP)
  • Permissões de acesso incorretas configuradas no servidor. (HTTP)
  • Você precisa estar autenticado (REST)

E a lista pode continuar com 'Erro no servidor 500 "(um erro HTTP HTTP do Apache / Nginx ou um erro de restrição de negócios no REST) ​​ou outros erros HTTP etc.

No código, é difícil entender qual foi o motivo da falha, uma falha HTTP (transporte) ou uma falha REST (lógica).

Se a solicitação HTTP foi fisicamente executada com sucesso, ela sempre deve retornar o código 200, independentemente dos registros encontrados ou não. Porque o recurso URI foi encontrado e foi tratado pelo servidor HTTP. Sim, pode retornar um conjunto vazio. É possível receber uma página da web vazia com 200 como resultado HTTP, certo?

Em vez disso, você pode retornar o código HTTP 200 com algumas opções:

  • objeto "error" no resultado JSON se algo der errado
  • Matriz / objeto JSON vazio se nenhum registro encontrado
  • Um sinalizador de resultado / sucesso booleano em combinação com as opções anteriores para uma melhor manipulação.

Além disso, alguns provedores de Internet podem interceptar suas solicitações e retornar um código HTTP 404. Isso não significa que seus dados não foram encontrados, mas há algo errado no nível do transporte.

Do Wiki :

Em julho de 2004, o provedor de telecomunicações do Reino Unido BT Group implantou o sistema de bloqueio de conteúdo Cleanfeed, que retorna um erro 404 a qualquer solicitação de conteúdo identificado como potencialmente ilegal pela Internet Watch Foundation. Outros ISPs retornam um erro "proibido" de HTTP 403 nas mesmas circunstâncias. A prática de empregar erros 404 falsos como forma de ocultar a censura também foi relatada na Tailândia e na Tunísia. Na Tunísia, onde a censura era severa antes da revolução de 2011, as pessoas tomaram conhecimento da natureza dos falsos erros 404 e criaram um personagem imaginário chamado "Ammar 404", que representa "o censor invisível".

Por que não simplesmente responder com algo assim?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

O Google sempre retorna 200 como código de status na API de geocodificação, mesmo que a solicitação falhe logicamente: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

O Facebook sempre retorna 200 para solicitações HTTP bem-sucedidas, mesmo se a solicitação REST falhar: https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

É simples, os códigos de status HTTP são para solicitações HTTP. A API REST é sua, defina seus códigos de status.

Marcodor
fonte
3
Na verdade, o uso de códigos de status HTTP para REST é ainda mais confuso: 1) você vê 4xx na caixa de ferramentas do desenvolvedor e não pode dizer apenas olhando para ele se o servidor retornou algum valor razoável ou se não conseguiu processar sua solicitação. e, em seguida, 2) todos os seus manipuladores de erro / exceção / captura devem verificar qual servidor retornou como resposta (principalmente não, pois você precisaria fazer isso em todas as chamadas de serviço) e muitas vezes 3) você recebe a mesma carga ( tipo) no caminho de sucesso e erro, levando a código complicado / duplicado ... Muito confuso.
Szczepanpp
9
Esta resposta confunde a semântica original do protocolo HTTP versus como o REST over HTTP como um estilo de arquitetura redireciona o HTTP para implementar APIs de serviço da web. Como um estilo arquitetural, o REST não é um padrão a ser rigorosamente seguido, é uma abordagem sugerida. O uso de uma resposta 200 para uma falha de validação não é certo ou errado; no entanto, é confuso para seus clientes responder que a solicitação foi bem-sucedida, mas realmente falhou devido a uma falha de validação, um detalhe importante que está oculto no corpo da resposta, a semântica que o cliente precisa analisar para entender.
Kevin Hooke
5
@ Marcodor, se sua chamada à API falhar, mas você retornar 200 indicando sucesso, como é uma boa ideia? não é claro e confuso para os consumidores da sua API.
Kevin Hooke
3
Corrija por vários motivos, não apenas a separação dos erros HTTP vs REST. A validação REST geralmente requer mais nuances. Por exemplo, registro aceito, mas sinalizado como duplicado vs. rejeitado por uma violação exclusiva do índice. Você também deseja um modelo de retorno consistente. O BadRequest()método .NET possui seu próprio modelo de retorno que será diferente do seu modelo de retorno regular. Isso é um pesadelo para analisar. @KevinHooke, retornar HTTP 200 para um erro de validação REST é como dizer: "Recebi sua mensagem, a resposta é não e eis o porquê". O retorno do HTTP 400 diz: "Não sei do que você está falando".
Neil Laslett
5
o argumento "porque o Google faz isso, deve estar certo" é uma loucura para mim ... é bom desafiar algo que o Google implementou para crianças. O retorno do HTTP 200 para uma chamada de repouso sem êxito confunde o chamador da API, que deve ser 4xx e pode-se incluir um bonito JSON / XML no corpo ... vamos interromper a loucura.
precisa
43

Uma duplicata no banco de dados deve ser a 409 CONFLICT.

Eu recomendo usar 422 UNPROCESSABLE ENTITYpara erros de validação.

Eu dou uma explicação mais longa dos códigos 4xx aqui .

Phil Parker
fonte
6

O Código de Status 304 Não Modificado também daria uma resposta aceitável a uma solicitação duplicada. Isso é semelhante ao processamento de um cabeçalho do If-None-Matchuso de uma tag de entidade.

Na minha opinião, a resposta de @ Piskvor é a escolha mais óbvia para o que percebo ser a intenção da pergunta original, mas tenho uma alternativa que também é relevante.

Se você deseja tratar uma solicitação duplicada como um aviso ou notificação, e não como um erro, um código de status de resposta 304Não Modificado e o Content-Locationcabeçalho que identifica o recurso existente também são válidos. Quando a intenção é apenas garantir a existência de um recurso, uma solicitação duplicada não seria um erro, mas uma confirmação. A solicitação não está errada, mas é simplesmente redundante, e o cliente pode se referir ao recurso existente.

Em outras palavras, a solicitação é boa, mas como o recurso já existe, o servidor não precisa executar nenhum processamento adicional.

Suncat2000
fonte
6
Pelo que entendi, 304 é destinado a operações GET para auxiliar no armazenamento em cache.
Sinaesthetic
6

O adaptador ActiveRecord da Ember-Data espera 422 UNPROCESSABLE ENTITYser retornado do servidor. Portanto, se seu cliente estiver escrito em Ember.js, você deverá usar 422. Somente o DS.Errors será preenchido com erros retornados. Obviamente, você pode alterar 422 para qualquer outro código no seu adaptador.

Daniel Kmak
fonte