¿Debería "No Resultados" ser un error en una respuesta RESTful?

52

Describiré un ejemplo:
empiezo a hacer una API para una panadería. La API permitirá a las personas buscar en su catálogo productos para hornear, como el uso de galletas caseras de menta con chispas de chocolate api.examplebakery.com/search?q=......

Alguien usa esto para buscar un producto llamado pineapple-banana flavoured cookiesy obviamente no encontrará ningún resultado.

¿Debería devolverse esto como un error? La búsqueda no falló, la API buscó y concluyó con éxito que no se encontraron cookies. La API no debe regresar 404, porque la API fue encontrada.

Berry M.
fuente
51
204 Sin contenido
AakashM
66
Posible duplicado de RESTful API representa la ausencia de una cosa
mosquito
3
@gnat: Esto no es un duplicado, porque la otra pregunta es sobre un recurso específico, no una consulta contra múltiples recursos.
Greg Burghardt
77
Análogamente, suponga que tiene una función que devuelve una matriz de objetos. Si no hay ningún objeto que coincida con un caso de uso en particular, ¿preferiría la función a través de una excepción o devolvería una matriz vacía?
Kevin - Restablece a Monica el
2
@AakashM Devolver HTTP-204 a una solicitud GET es bastante inusual, sé que no lo he visto en ningún lado. Hasta donde sé, HTTP-204 se usa generalmente como respuesta al modificar un recurso en el servidor, por ejemplo, solicitudes POST / PUT / DELETE.
Radu Murzea

Respuestas:

122

Cuando hay resultados, la salida es una lista (JSON, basada en su comentario). Para consultas sin resultados, el resultado debe ser exactamente el mismo. La lista simple tiene 0 elementos.

Entonces, si su respuesta es normalmente esto:

{
    "results": [
        {
            "name": "Pancakes",
            ....
        },
        {
            "name": "French Fries",
            ....
        }
    ]
}

Luego, para una consulta con 0 resultados, debería ser esto:

{
    "results": []
}

Si también incluye metadatos sobre cuántas "páginas" de resultados hay, enlaces a esas "páginas", etc., sugeriría decir que hay 1 "página".

El estado HTTP debe ser el mismo que cuando hay resultados 200 OK.

204 No ContentTambién puede parecer una opción, pero no se debe a que de hecho está devolviendo "contenido": la lista vacía. Si cree que una lista vacía no cuenta como "contenido", ¿qué sucede si luego modifica la respuesta para ofrecer sugerencias de ortografía? El núcleo de la respuesta seguirá siendo una lista vacía, pero ahora hay aún más "contenido".

Para obtener más información útil sobre los códigos de estado HTTP, vale la pena leer su respuesta jpmc26 .

Jory Geerts
fuente
99
Este es el mismo tipo de pensamiento que el patrón de objeto nulo . Los errores y nulos no son la única forma de decir que no hay nada aquí. A veces quieres expresar tu nada en silencio. De esa manera, los clientes no tienen que probar nada.
candied_orange
54
Yo diría que devolver un 204 es inapropiado, ya que está devolviendo contenido. Es solo que el contenido no tiene resultados, lo cual es distinto de no devolver ningún contenido.
TMN
99
@ TMN estuvo de acuerdo: 204 no es apropiado para "ningún resultado". Su consulta siempre debe devolver una matriz, con los resultados dentro de la matriz. Si no hay resultados, el cliente lo manejará de forma natural. Si el cliente quiere mostrar texto especial ("No se encontraron resultados"), entonces está bien. 204 solo debe devolverse para un punto final que no devuelve naturalmente un resultado.
JasonB
1
Se podría utilizar 204 si se devuelva NULL serializado como un reconocimiento cadena vacía I
Ewan
15
Esta. Lo importante al construir una API RESTful es la parte de la API, no la tranquilidad. Una buena API facilita la vida de los clientes / consumidores. Una matriz vacía es más fácil de manejar que los valores nulos / excepciones / códigos de estado.
Guran
37

Siempre que elija un código HTTP, siempre debe hacer esta pregunta:

¿Qué puede / hará / debería hacer cualquier cliente arbitrario con la respuesta?

  1. ¿El cliente siempre debe tratar la respuesta como un fracaso? Entonces desea 4xx o 5xx, dependiendo de si el problema es la entrada del cliente o los procesos del servidor.
  2. ¿Debería el cliente hacer una solicitud en otro lugar? Entonces 3xx es para ti.
  3. ¿El servidor hizo lo que el cliente le pidió (tuvo éxito)? Eso es 2xx.

Siempre decida en qué rango debe estar primero su código de respuesta. Hacerlo rápidamente elimina muchos códigos de respuesta como opciones, y (quizás lo más importante) hace que seguir la semántica de los códigos sea mucho más simple. Consulte las secciones iniciales de la documentación del código HTTP para ver las explicaciones de lo que representa cada categoría de códigos.

En este caso, el cliente solicitó una lista de resultados con un filtro de un punto final válido y existente y tiene autorización para acceder a él. El servidor pudo procesar la solicitud y determinar los datos apropiados para devolver (sin elementos), por lo que la solicitud se realizó correctamente. Simplemente sucede que el filtro que dieron filtró todos los resultados. No depende del servidor determinar si esto es lo que el cliente quería o no, ya que puede ser un resultado esperado para algunos clientes. Si de alguna manera es un problema para el código del cliente, es responsabilidad del cliente determinar, verificar y manejar adecuadamente. Entonces esto es claramente 2xx.

Ahora la pregunta es, "¿Qué 2xx?" Esto depende de cómo intente que responda el servidor.

  • ¿Enviarás una representación de una lista vacía, como describen otras respuestas ? Si es así, desea 200. 200 significa que el servidor no experimentó problemas y tiene una representación de los resultados para que el cliente los consuma. Esta es probablemente la forma más conveniente de responder para sus consumidores, quienes simplemente pueden analizar la respuesta si hubo resultados o no y luego descubrir cómo manejar ellos mismos una lista vacía.
  • 204 no es semánticamente incorrecto aquí, pero tendría que responder sin ningún cuerpo de mensaje . Esto significa que todo el código del cliente tendría que verificar explícitamente los diferentes códigos HTTP (o al menos por la falta de un cuerpo de mensaje) y manejarlos por separado. Es inconveniente y es más probable que conduzca a clientes con mal comportamiento.

Los otros no son aplicables en absoluto:

  • 201 está fuera de la cuestión. No creó ningún recurso persistente y no está devolviendo una ubicación a un recurso creado.
  • 202 está fuera de la cuestión. La solicitud está hecha; No se está procesando en segundo plano.
  • 203 significa que la respuesta se modificó entre el servidor autorizado y el cliente. Su interfaz RESTful es el servidor autorizado, por lo que esto no se aplica aquí.
  • 205 no tiene sentido. No necesita que el cliente borre o actualice nada.
  • 206 parece estar diseñado para devolver un gran recurso a través de múltiples respuestas. También requiere que el cliente solicite una parte del contenido en los encabezados (por lo que la paginación a través de cadenas de consulta no califica). No aplica aquí.

Por lo tanto, debería ser 200 o 204, y es más probable que 200 conduzca a un código de cliente más simple y robusto (especialmente si usa una estructura de respuesta consistente que contiene una lista vacía).

jpmc26
fuente
55
Estaría interesado en la opinión del downvoter. No creo que nada de esto sea controvertido.
jpmc26
2
No creo que los clientes tengan que verificar 204 explícitamente. Todo lo que necesitan es la capacidad de manejar el objeto de respuesta nula. Es el trabajo del marco HTTP manejar 204 omitiendo la parte "analizar el cuerpo". 200 con Content-Lenght 4 y body null es lo mismo.
Agent_L
1
@Agent_L Tiene razón en que si el servidor responde con una estructura inconsistente con la respuesta normal (como poner nulldonde normalmente hay una lista), no obtendrá los beneficios de la coherencia incluso con 200. Sin embargo, lo que describo es usar un respuesta que es consistente con la estructura normal y tiene una lista vacía donde normalmente iría la lista de resultados. 204 elimina cualquier oportunidad de tener una respuesta tan consistente. Además, incluso en las bibliotecas de cliente HTTP que tienen funciones convenientes, a menudo (¿típicamente?) Tiene que hacer una llamada explícita para analizar JSON.
jpmc26
@Agent_L En particular con las listas, las personas que llaman a menudo pueden dejar que su código se ejecute normalmente sobre una lista vacía (por ejemplo, haciendo un bucle), mientras que necesitarían una verificación explícita de algún tipo para manejar otro tipo de representación.
jpmc26
16

No. El uso de 404 para indicar 'su consulta fue procesada pero no hubo coincidencias' es horrible porque:

  • flujo condicional basado en el manejo de excepciones (es decir, forzar un resultado no excepcional para crear y manejar una excepción en el cliente que puede ser no productiva e incómoda)

  • ambigüedad entre la página 'real' no encontrada, escribió los errores incorrectos del punto final

Lo que debe recordar es que siempre hay un cliente para deserializar el mensaje y lo que el cliente devuelve es lo importante; No la serialización.

Si el cliente debe devolver nulo, utilice la serialización de nulo. Si el cliente debe devolver una matriz vacía, use [], si el cliente arroja un error use 500 y pase el mensaje de error

Ewan
fuente
2
¿Por qué debería importarle al servidor lo que el cliente está haciendo con la información? (PD: no fui yo quien rechazó tu respuesta).
Radu Murzea
en este contexto, el "cliente" es el código que se ejecuta en el dispositivo cliente que expone el servicio a la aplicación cliente. Tiene que poder exponer los métodos de los servicios y devolver los resultados según lo previsto por el servicio. Necesita un par cliente-servidor para que la comunicación funcione en absoluto
Ewan
3
No use 5xx para errores del cliente , por supuesto. Prefiero 4xx en ese caso.
Kevin
1
Aunque, ¿no debería ser "servidor", no "cliente" en la mayoría de estos casos? ¿Es el servidor el que procesa la solicitud y sirve una respuesta, el cliente solo procesa la respuesta? ¿En qué caso un código 5xx estaría bien, ya que es un error del servidor, no un error del cliente?
MrWhite
2
El problema con todos los códigos de error es que tienen significado dentro de http. 500 es el único código adecuado para cuando su servicio lanza una excepción
Ewan
9

Más allá de la muy buena respuesta de @ Ewan:

Si la consulta es del tipo que devuelve un conjunto de resultados, entonces el conjunto vacío es lógicamente tan apropiado como un conjunto de uno o un conjunto de más. En términos generales, por las razones que @Ewan afirma, hace más daño que bien alterar el conjunto vacío en un error, y es simplemente innecesario.

Si la consulta es del tipo que busca y devuelve un singleton específico (que se espera encontrar, por ejemplo, coincidencia exacta por id), entonces no encontrado es una posible respuesta lógicamente apropiada.

Erik Eidt
fuente
Sí, pensé exactamente eso en la respuesta de Ewan.
Walfrat
5

Asume que el código debe tomar una acción especial cuando no se devuelven datos, pero ese podría no ser el caso. El código podría simplemente estar buscando un recuento de productos o agregar los resultados a una lista o cualquier cantidad de cosas. Solo debe dar un "error" a un usuario si realmente hay un error.

John Smith
fuente
3
"Solo debe dar un" error "a un usuario si realmente hay un error". - esta. Un conjunto de resultados vacío al realizar una "búsqueda" no suele ser un "error". Sin embargo, si la conexión de la base de datos fallaba, eso significaba que la búsqueda no podía realizarse realmente, entonces un conjunto de resultados vacío (y ningún error) sería ambiguo. Algún tipo de estado de error sería apropiado en este caso (quizás junto con un conjunto de resultados vacío, dependiendo de cómo se defina la API).
MrWhite
0

Cuando uso una API, como cliente tengo que manejar casos de "éxito" diferentes a los casos de "error"; No tengo otra opción allí. Por lo tanto, debe devolver un error en situaciones que el cliente desea tratar de manera diferente, y el éxito en situaciones que el cliente desea tratar de la misma manera.

Si hago una consulta que, en teoría, podría devolver cualquier número de resultados, cero, uno, doscientos, etc., entonces debería devolver "éxito" siempre que la API entregue la lista completa de todos los resultados. Y, posiblemente, en los casos en que haya muchos resultados, devolvió una lista parcial de resultados para evitar un tamaño excesivo, y hay una forma acordada de cómo obtendría los otros resultados. Eso es porque, como cliente, a menudo quiero manejar el caso de cero resultados como el caso de más resultados. Podría tratarlo de manera diferente, pero no quiero que me obliguen a hacerlo.

Es diferente en el caso de que busque un valor. Espero exactamente un resultado, el valor que estoy buscando. Y necesito ese resultado para continuar lo que quiero hacer de una manera significativa. Aquí es mucho más aceptable devolver un estado 404 para el caso de que no haya ningún valor, porque de todos modos necesito manejar ese caso de manera diferente.

Resumen: si el cliente espera cualquier número de resultados, de cero a números grandes, devuelva "éxito" si se entregan todos los resultados, incluso si el número es cero. Si el cliente espera exactamente un resultado, devuelva el éxito si se encuentra el resultado y un error si no se encuentra el resultado.

gnasher729
fuente