Devo retornar um status HTTP 400 (Bad Request) se um parâmetro estiver sintaticamente correto, mas violar uma regra comercial?

36

Digamos que eu tenha um ponto de extremidade REST que use um inteiro como parâmetro:

/makeWaffles?numberOfWaffles=3

Neste caso, quero que o número seja positivo porque não posso gerar um número negativo de waffles (e solicitar 0 waffles é uma perda de tempo). Portanto, desejo rejeitar qualquer solicitação que não contenha um número inteiro positivo. Também quero rejeitar uma solicitação que exceda um número inteiro máximo (digamos que, por enquanto, seja MAX_INTEGER).

No caso de alguém solicitar um número não positivo de waffles, devo retornar um status HTTP 400 (Bad Request)? Meu pensamento inicial é sim: não é um número válido para eu completar o pedido. No entanto, o RFC não menciona regras comerciais como um motivo para lançá-lo:

The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

Uma regra de negócios não se enquadra em nenhum desses três exemplos. É sintaticamente correto, está enquadrado corretamente e não é um roteamento enganoso de solicitações.

Então, devo retornar um status HTTP 400 (Bad Request) se um parâmetro estiver sintaticamente correto, mas violar uma regra comercial? Ou há um status mais apropriado para retornar?

    
por Thunderforge 24.08.2016 / 21:45
fonte

5 respostas

24

Esta é uma ótima pergunta, e ainda altamente relevante, dado o contexto histórico (e definições aparentemente contraditórias) dos códigos de retorno HTTP. Mesmo entre as respostas a essa pergunta, existem definições conflitantes. Isso pode ser esclarecido movendo-se cronologicamente.

RFC 2616 (junho de 1999)

10.4.1 400 Bad Request

The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.

A partir desse RFC, esse código de status aplica-se especificamente apenas a solicitações sintaticamente inválidas. Houve uma lacuna nos códigos de status para validação semântica. Assim, quando o RFC 4918 apareceu, um novo código nasceu.

RFC 4918 (junho de 2007)

11.2. 422 Unprocessable Entity

The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

422 Entidade não processável foi criada para preencher a lacuna de validação semântica na especificação original dos códigos de status 4xx. No entanto, outro RFC relevante surgiu em 2014, o que generalizou 400 para não ser mais específico da sintaxe .

RFC 7231 (junho de 2014, explicitamente obsoleta a RFC 2616)

6.5.1. 400 Bad Request

The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

Observe que a descrição da 422 diz que a razão 400 é inadequada é porque 400 (como na RFC 2616) deve ser retornado apenas para a sintaxe de solicitação incorreta. No entanto, a partir do RFC 7231, a definição estrita do erro de sintaxe não se aplica mais a 400 .

Voltemos à questão: Embora 422 seja tecnicamente mais específico, considerando este contexto, pude ver 400 ou 422 sendo usado para validação semântica dos parâmetros da API. Eu hesito em usar 422 em minhas próprias APIs porque a definição de 422 está tecnicamente desatualizada neste momento (embora eu não saiba se isso é reconhecido oficialmente em algum lugar). O artigo mencionado na resposta aceita foi escrito em 2012, dois anos antes de o RFC 7231 ter esclarecido o HTTP 400. Só não se esqueça de padronizar um ou outro.

    
por 24.02.2017 / 15:51
fonte
40

Eu li a primeira resposta e realmente não concordei com ela porque, pelo menos na minha leitura, um pedido incorreto (400) significa: "Eu não consigo nem atender ao seu pedido porque algo está fundamentalmente errado." E eu encontrei este post que defende o retorno de um 422.

do IETF

422 Entidade não processável (WebDAV; RFC 4918) A solicitação foi bem formada, mas não pôde ser seguida devido a erros semânticos

Essa parece ser uma resposta mais apropriada, já que sua solicitação é bem formada, mas não passa nas regras de validação.

    
por 24.08.2016 / 22:09
fonte
7

Sim, a entrada que não segue o contrato implícito do terminal é "algo percebido como um erro do cliente" e deve retornar 400.

As exceções para isso são se a regra comercial estiver relacionada à segurança (então, 401 Unauthorized ou 403 Forbidden seria melhor). Alternativamente, se enviar um 400 vazaria informações sobre a existência de algo, e então um 404 Not Found poderia ser mais apropriado.

    
por 24.08.2016 / 21:57
fonte
7

Não, você não deveria. Os códigos HTTP são destinados à camada HTTP do seu aplicativo. As regras de negócios são camadas completamente diferentes e são específicas do aplicativo, portanto, é necessário criar seu próprio "protocolo".

Imagine que um apocalipse acontece e você tem que mudar do protocolo HTTP para o uso de pombos. Pombos não têm códigos de retorno, então você precisa mudar sua camada de negócios para acomodar isso. Mas a sua empresa não mudou realmente de forma alguma, por isso você não precisa mudar a camada de negócios. Ele mostra um acoplamento entre essas duas camadas (transporte e negócios).

Voltar para a pergunta: O que você deve fazer é retornar "200 OK" com um corpo descrevendo o que aconteceu com a solicitação. A especificação diz claramente isso:

link .

200 OK

The request has succeeded. The information returned with the response is dependent on the method used in the request, for example

POST an entity describing or containing the result of the action;

Sua solicitação HTTP foi bem-sucedida? Sim, o servidor web sabe o que fazer com essa solicitação (por exemplo, passá-lo para a parte do servidor do seu aplicativo). O servidor da Web passa essa solicitação para a parte do servidor do seu aplicativo, que pega os dados POSTed, os processa (valida-os no seu caso) e retorna uma resposta normal (no corpo de uma resposta HTTP) para a parte do cliente do seu aplicativo . Essa resposta da parte do servidor do aplicativo pode ser "Ótimo, os dados que você me enviou são válidos" ou "Sinto muito, os dados que você enviou não são válidos". E cabe ao seu cliente parte do aplicativo entender o que a resposta significa.

PS: "400 Solicitação incorreta" significa que o servidor da web não entendeu o que você quer dela. Isso significa que a parte do servidor do seu aplicativo nem recebeu a solicitação. Ou pelo menos é isso que significa: -)

EDIT : Acabei de perceber que você está fazendo uma solicitação GET, não POST. Essa é uma má ideia porque o GET não deve alterar o estado do aplicativo. GET deve simplesmente recuperar dados do servidor. Mas no seu pedido você está realmente mudando o estado do aplicativo, então você realmente deveria estar usando o POST.

    
por 07.03.2017 / 12:43
fonte
-3

Não tenho certeza de que todos concordariam, mas estamos usando o 409 - Conflito. Muitos afirmam que o 409 é mais um conflito com o estado do sistema, mas aceitamos a interpretação de que um conflito de valores de dados fora do intervalo aceito é corrigível pelo solicitante e um uso aceitável de 409. 422 Eu acho que seria razoável como o pedido está corretamente formado, mas não pode ser processado conforme solicitado. Eu opino no entanto, se você não deseja implementar uma série de respostas, apenas dar um 400 ainda é aceitável.

    
por 24.08.2016 / 22:47
fonte