¿Debo devolver un estado HTTP 400 (Solicitud incorrecta) si un parámetro es sintácticamente correcto, pero viola una regla comercial?

56

Digamos que tengo un punto final REST que toma un entero como parámetro:

/makeWaffles?numberOfWaffles=3

En este caso, quiero que el número sea positivo porque no puedo hacer un número negativo de gofres (y solicitar 0 gofres es una pérdida de tiempo). Por lo tanto, quiero rechazar cualquier solicitud que no contenga un entero positivo. También quiero rechazar una solicitud que exceda un número entero máximo (digamos por ahora que es MAX_INTEGER).

En el caso de que alguien solicite un número no positivo de gofres, ¿debo devolver un estado HTTP 400 (Solicitud incorrecta)? Mi pensamiento inicial es sí: no es un número válido para completar la solicitud. Sin embargo, el RFC no menciona las reglas comerciales como una razón para lanzarlo:

El código de estado 400 (Solicitud incorrecta) indica que el servidor no puede o no procesará la solicitud debido a algo que se percibe como un error del cliente (por ejemplo, sintaxis de solicitud con formato incorrecto, enmarcado de mensaje de solicitud no válido o enrutamiento de solicitud engañoso).

Una regla de negocios no se incluye en ninguno de esos tres ejemplos. Es sintácticamente correcto, está enmarcado correctamente y no es una ruta de solicitud engañosa.

Entonces, ¿debo devolver un estado HTTP 400 (Solicitud incorrecta) si un parámetro es sintácticamente correcto, pero viola una regla comercial? ¿O hay un estado más apropiado para regresar?

Forja del Trueno
fuente

Respuestas:

38

Esta es una gran pregunta, y sigue siendo muy relevante dado el contexto histórico (y definiciones aparentemente contradictorias) de los códigos de retorno HTTP. Incluso entre las respuestas a esta pregunta hay definiciones contradictorias. Esto se puede aclarar moviéndose cronológicamente.

RFC 2616 (junio de 1999)

10.4.1 400 Solicitud incorrecta

El servidor no pudo entender la solicitud debido a una sintaxis incorrecta. El cliente NO DEBE repetir la solicitud sin modificaciones.

A partir de este RFC, este código de estado se aplica específicamente solo a solicitudes sintácticamente inválidas. Hubo una brecha en los códigos de estado para la validación semántica. Por lo tanto, cuando apareció RFC 4918, nació un nuevo código.

RFC 4918 (junio de 2007)

11.2 422 Entidad no procesable

El código de estado 422 (entidad no procesable) significa que el servidor comprende el tipo de contenido de la entidad de solicitud (por lo tanto, un código de estado 415 (tipo de medio no admitido) es inapropiado) y la sintaxis de la entidad de solicitud es correcta (por lo tanto, un 400 (solicitud incorrecta) ) el código de estado es inapropiado) pero no pudo procesar las instrucciones contenidas. Por ejemplo, esta condición de error puede ocurrir si un cuerpo de solicitud XML contiene instrucciones XML bien formadas (es decir, sintácticamente correctas), pero semánticamente erróneas.

422 Entidad no procesable se creó para llenar el vacío de validación semántica en la especificación original de los códigos de estado 4xx. Sin embargo, se produjo otro RFC relevante en 2014 que generalizó 400 para que ya no sea específico de la sintaxis .

RFC 7231 (junio de 2014, explícitamente obsoletos RFC 2616)

6.5.1. 400 Petición Incorrecta

El código de estado 400 (Solicitud incorrecta) indica que el servidor no puede o no procesará la solicitud debido a algo que se percibe como un error del cliente (por ejemplo, sintaxis de solicitud con formato incorrecto, enmarcado de mensaje de solicitud no válido o enrutamiento de solicitud engañoso).

Tenga en cuenta que la descripción de 422 dice que la razón por la que 400 es inapropiada es porque 400 (a partir de RFC 2616) debe devolverse solo por una sintaxis de solicitud incorrecta. Sin embargo, a partir de RFC 7231, la definición estricta de error de sintaxis ya no se aplica a 400 .

Volviendo a la pregunta en cuestión: si bien 422 es técnicamente más específico, dado este contexto, pude ver que 400 o 422 se usan para la validación semántica de los parámetros API. Dudo en usar 422 en mis propias API porque la definición de 422 está técnicamente desactualizada en este momento (aunque no sé si eso se reconoce oficialmente en alguna parte). El artículo al que se hace referencia en la respuesta de Fran que alienta el uso de 422 fue escrito en 2012, dos años antes de que RFC 7231 aclarara HTTP 400. Solo asegúrese de estandarizar uno u otro.

Kyle McVay
fuente
42

Leí la primera respuesta y realmente no estuve de acuerdo con ella porque, al menos en mi lectura, una solicitud incorrecta (400) significa: "Ni siquiera puedo manejar su solicitud porque algo está fundamentalmente mal". Y encontré esta publicación que justifica la devolución de un 422.

de IETF

422 Entidad no procesable (WebDAV; RFC 4918) La solicitud estaba bien formada pero no se pudo seguir debido a errores semánticos

Esto parece una respuesta más apropiada ya que su solicitud está bien formada, pero no pasa sus reglas de validación.

Fran
fuente
55
Lo escuché descrito como "400 significa mala sintaxis, 422 significa mala semántica".
cbojar
33
Todos los códigos x00 son códigos genéricos "catch all". Un 400 no es inapropiado , solo menos específico .
Jack
1
Buena respuesta, pero la respuesta dada por @GoFree tiene más sentido para mí.
Ewerton
2
Hay un caso realmente fuerte para los códigos de retorno que todos conocen. Absolutamente todos necesitarán buscar 422, y apuesto a que la mayoría todavía no sabrá qué hacer con él.
sylvanaar
9

No, no deberías. Los códigos HTTP están destinados a la capa HTTP de su aplicación. Las reglas de negocio son completamente diferentes y son específicas de la aplicación, por lo que debe crear su propio "protocolo".

Imagina que sucede un apocalipsis y tienes que cambiar del protocolo HTTP a usar Pigeons. Las palomas no tienen ningún código de retorno, por lo que deberá cambiar su capa de negocios para adaptarse a eso. Pero su negocio realmente no ha cambiado de ninguna manera, por lo que no debería necesitar cambiar la capa empresarial. Muestra un fuerte acoplamiento entre esas dos capas (transporte y negocios).

Volver a la pregunta: lo que debe hacer es devolver "200 OK" con un cuerpo que describa lo que sucedió con la solicitud. La especificación lo dice claramente:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1 .

200 OK

La solicitud ha sido exitosa. La información devuelta con la respuesta depende del método utilizado en la solicitud , por ejemplo

PUBLICAR una entidad que describa o contenga el resultado de la acción;

¿Tu solicitud HTTP tuvo éxito? Sí, el servidor web sabe qué hacer con esa solicitud (por ejemplo, pasarla a la parte del servidor de su aplicación). El servidor web luego pasa esta solicitud a la parte del servidor de su aplicación, que toma los datos PUBLICADOS, los procesa (los valida en su caso) y devuelve una respuesta normal (en el cuerpo de una respuesta HTTP) a la parte del cliente de su aplicación . Esta respuesta de la parte del servidor de la aplicación puede ser "Excelente, los datos que me envió son válidos" o "Lo siento, los datos que envió no son válidos". Y depende de su cliente parte de la aplicación comprender lo que significa la respuesta.

PD: "400 Bad Request" significa que el servidor web no entendió lo que quieres de él. Significa que su servidor parte de su aplicación ni siquiera recibió la solicitud. O al menos eso es lo que significa :-)

EDITAR : Me acabo de dar cuenta de que estás haciendo una solicitud GET, no POST. Esta es una mala idea porque GET no debería cambiar el estado de la aplicación. Se supone que GET simplemente recupera datos del servidor. Pero en su solicitud, en realidad está cambiando el estado de la aplicación, por lo que realmente debería usar POST.

Ir libre
fuente
1
Sí, devolver 404 en ese caso está bien. No estoy diciendo que el servidor siempre deba enviar 200 OK con una explicación en el cuerpo.
GoFree
Mejor explicación que he visto hasta ahora. Tengo esta misma pregunta y parece que toda la palabra piensa diferente de mí y de ti @GoFree
Ewerton
@GoFree Esta es una muy buena respuesta para repensar el diseño de API. ¿Pero no es el caso, que usamos HTTP y su código de respuesta como parte eminente de la capa de reglas de negocio cuando usamos una API REST?
Thomas Lauria
1
@Thomas Lauria Todavía no he visto una implementación adecuada de RESTFUL API. Sin embargo, REST API es una palabra de moda hoy en día, por lo que cada empresa tiene que usarla (la palabra, no la tecnología) sin comprender realmente el concepto detrás de ella. Entonces sí, se está utilizando de manera incorrecta en todas partes. Lo que los programadores suelen crear no es una API REST, sino una API HTTP o API OVER HTTP. En realidad, una de las pocas implementaciones RESTFUL buenas es el propio HTTP :)
GoFree
1
El uso de 200-OK es especialmente lógico si la aplicación incluye un campo de "error" en el cuerpo de la respuesta para describir cualquier error de nivel comercial, como un valor de entrada demasiado alto o demasiado bajo o faltante, producto agotado, etc.
Roland
8

Sí, la entrada que no sigue el contrato implícito del punto final es "algo que se percibe como un error del cliente" y debe devolver 400.

Las excepciones a esto son si la regla de negocio está relacionada con la seguridad (entonces 401 Unauthorizedo 403 Forbiddensería mejor). Alternativamente, si enviar un 400 filtraría información sobre la existencia de algo, y luego 404 Not Foundpuede ser más apropiado.

Telastyn
fuente
-3

No estoy seguro de que todos estén de acuerdo, pero estamos usando 409 - Conflicto. Muchos afirman que el 409 es más un conflicto con el estado del sistema, pero aceptamos la interpretación de que un conflicto de valores de datos que están fuera del rango aceptado es reparable por el solicitante y un uso aceptable de 409. 422 Creo que sería razonable como la solicitud está formado correctamente pero no se puede procesar según lo solicitado. Sin embargo, opino que si no desea implementar una gran cantidad de respuestas, simplemente dar 400 todavía es aceptable.

dlb
fuente
55
409 significa "el estado en el que está tratando de poner esto está en conflicto con el estado en el que otro cliente está tratando de poner esto", es para bloquear escrituras concurrentes (usando ETags, por ejemplo)
Jack