¿Debería una API REST devolver un error interno del servidor 500 para indicar que una consulta hace referencia a un objeto que no existe?

39

Estoy trabajando con una API REST que reside en un servidor que maneja datos para una multitud de dispositivos IoT.

Mi tarea es consultar al servidor utilizando la API para recopilar información de rendimiento específica sobre dichos dispositivos.

En un caso, obtengo una lista de dispositivos disponibles y sus identificadores correspondientes, luego consulto al servidor para obtener más detalles utilizando esos identificadores (GUID).

El servidor está devolviendo una 500 Internal Server Errorconsulta sobre uno de esos ID. En mi aplicación, se produce una excepción y no veo detalles sobre el error. Si examino la respuesta más de cerca con Postman , puedo ver que el servidor devolvió JSON en el cuerpo que contiene:

errorMessage: "This ID does not exist".

Para empezar, ignore el hecho de que el servidor proporcionó la ID; ese es un problema separado para el desarrollador.

¿Debería una API REST devolver a 500 Internal Server Errorpara informar que una consulta hace referencia a un objeto que no existe? En mi opinión, los códigos de respuesta HTTP deberían referirse estrictamente al estado de la llamada REST, más que a la mecánica interna de la API. Esperaría un 200 OKcon la respuesta que contiene el error y la descripción, que sería propiedad de la API en cuestión.


Se me ocurre que hay una diferencia potencial en las expectativas dependiendo de cómo se estructura la llamada REST.

Considere estos ejemplos:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

En el primer caso, la ID del dispositivo se pasa como una variable GET. Un 404 o 500 indicaría que la ruta ( /restapi/deviceinfo) no se encuentra o da como resultado un error del servidor.

En el segundo caso, la ID del dispositivo es parte de la URL. Sería más comprensivo de a 404 Not Found, pero aún podría argumentar en función de qué partes de la ruta se interpretan como variables frente a puntos finales.

JYelton
fuente
¿Esta condición que estás describiendo se considera un éxito o un fracaso?
Robert Harvey
3
relacionado (posiblemente un duplicado): ¿Debo devolver una respuesta 204 o 404 cuando no se encuentra un recurso?
mosquito
@RobertHarvey Esperaba que la API devolviera alguna información sobre el dispositivo. La consulta en sí misma debería haber sido un éxito, pero el ID del dispositivo que se perdió no debería causar una falla en el nivel de solicitud.
JYelton
18
Una identificación que no existe me suena como un 404. La razón más común para los 500 errores es que los programadores permiten que surja una excepción interna para que el servidor de hosting pueda manejarla. A veces hay casos realmente excepcionales en los que eso sucede y, a veces, es solo una programación perezosa. Es difícil decir qué está pasando aquí.
Berin Loritsch el
9
El servidor interno 500 significa "es nuestra culpa, hemos estropeado algo", y nunca debe intentar devolver este estado a un usuario. Su propósito es básicamente indicar un error: su usuario puede decir que obtiene un 500 cuando realiza una solicitud en particular, y luego puede ingresar y solucionarlo.
berry120

Respuestas:

96

Creo que una respuesta 404 es la mejor coincidencia semántica aquí, porque no se encontró el recurso que estaba tratando de encontrar (como lo representa el URI utilizado para la consulta). Devolver una carga de error en el cuerpo es razonable, pero no es obligatorio.

De acuerdo con RFC 2616 , la definición del código de estado 404 es:

10.4.5 404 No encontrado
El servidor no ha encontrado nada que coincida con el URI de solicitud. No se indica si la condición es temporal o permanente. El código de estado 410 (Gone) DEBE usarse si el servidor sabe, a través de algún mecanismo internamente configurable, que un recurso antiguo no está disponible permanentemente y no tiene dirección de reenvío. Este código de estado se usa comúnmente cuando el servidor no desea revelar exactamente por qué se rechazó la solicitud o cuando no se aplica ninguna otra respuesta.

Andy Hunt
fuente
66
404 es solo una coincidencia semántica si la identificación que no existe corresponde al recurso que se está recuperando.
Robert Harvey
55
@ThomasOwens Una consulta que no devuelve resultados devolvería el estado 200 y una matriz vacía de resultados. Un 404 solo se devolverá cuando se especifique un ID de objeto específico que en realidad no existe.
Sean Burton el
11
@ThomasOwens: desde la perspectiva de la persona que llama, el punto final no lo es /questions, es /questions/368213. Ese punto final no existe en su escenario. Piénselo de esta manera: si realiza un GET en / foo / bar y no hay barra, ¿por qué la respuesta debería ser diferente si / foo existe o no?
Bryan Oakley
17
Correcto, no es un error del servidor, por lo que no enviamos un 5xx. Es un error del cliente: el cliente pidió algo que no tiene, por lo que enviamos 4xx, específicamente 404.
bdsl
77
@ThomasOwens: How do you differentiate between a 404 meaning "the query returned no results" and a 404 meaning "the endpoint does not exist"?- 400 Solicitud incorrecta.
Robert Harvey
34

Usaré tus ejemplos.

http://example.com/restapi/deviceinfo?id=123

Si el punto final devuelve una matriz json , la mejor opción es 200 OKcon una matriz vacía si no se encuentra ningún resultado.

Si el punto final está diseñado para devolver un único resultado , mi elección sería 404 NOT FOUND, pues, para mí, la sintaxis correcta para este tipo de punto final es: http://example.com/restapi/deviceinfo/123. Usualmente uso request param solo para filtrar y cuando mi punto final devuelve una matriz.

http://example.com/restapi/device/123/info

Creo que esta pregunta ya fue respondida aquí . POST o GET, la mejor opción parece 404 NOT FOUNDporque 123no se encontró el recurso .

En ambos casos, no puedo ver la necesidad de explicar la razón por la cual la solicitud no se completó. La información de solicitud y el código HTTP ya explican por qué.

Dherik
fuente
2
¿Cómo se distingue entre una identificación inexistente y una URL incorrecta?
Robert Harvey
2
@luizfzs, puedes hacerlo también, no puedo ver ningún problema al respecto. En algunas API que desarrollé, prefiero usar 204 en un PUT o DELETE exitoso ( como se explica aquí ) sin ningún cuerpo en respuesta.
Dherik
10
¿Por qué debería distinguir entre una identificación inexistente y una URL incorrecta, en ese nivel? De cualquier manera, todavía está haciendo una solicitud válida, en lo que respecta a HTTP. El servidor simplemente ... bueno ... no puede encontrar el recurso al que se dirige. Una URL incorrecta no es una solicitud con formato incorrecto; es una solicitud bien formada para lo incorrecto .
cHao
66
@cHao Porque como desarrollador, quiero saber si mi aplicación falla porque el elemento no existe, o si accidentalmente apunté mi aplicación a app.company.cxm / test / en lugar de app.company.cxm / tst /
Patrick M
77
@PatrickM: Como desarrollador, debe saber que las respuestas de error también pueden contener un cuerpo de mensaje. Ahí es donde va la información explicativa del error, si realmente lo desea. No rompas la semántica solo porque eres paranoico con los dedos gordos. En el nivel HTTP, no importa si te equivocaste /itms/1234o no /items/12234.
cHao
27

HTTP 404 es correcto, porque el servidor entiende qué recurso está pidiendo el cliente, pero no tiene ese recurso.

El hecho de que esté trabajando con una "API REST" es la clave. La API debería comportarse como si estuviera realizando una Transferencia de estado REpresentacional, no ejecutando una función. (Claro, el término "REST" ha llegado a tener un significado más amplio, pero aún puede usar su significado literal con buenos resultados aquí.) El cliente ha pedido el estado de un recurso descrito por la URL http://example.com/restapi/device/123/info. Una cadena de consulta ( /deviceinfo?id=123) no cambiaría la situación. El servidor sabe que está solicitando transferir el estado del dispositivo 123, pero no lo reconoce como un recurso conocido. Por lo tanto HTTP 404.

Las otras posibles respuestas discutidas aquí también tienen significados específicos:

  • HTTP 200- Tenemos el estado para ti; está en el cuerpo de respuesta.
  • HTTP 204- Tenemos el estado para ti; Está en blanco.
  • HTTP 400- No podemos decir qué recurso está preguntando. Repara tu URL.
  • HTTP 500- Funcionamos mal. No es tu culpa.

Ver RFC 2616 Sec. 10 según corresponda.

Travis Wilson
fuente
Estoy de acuerdo con tu opinión sobre esto. Si el servidor devolviera un 404, eso tendría más sentido que lo que está haciendo (un 500). Gracias.
JYelton
11

Un error 5xx se usa generalmente para indicar que el servidor encontró un error y no puede completar la solicitud. Si el servidor toma la solicitud, puede analizarla con éxito y luego hace su trabajo, eso no debería devolver un error 5xx.

No estoy seguro de si hay algún tipo de convención sobre qué devolver si una consulta no produce resultados. He visto tanto lo que usted describe (un 200 con un cuerpo que contiene un mensaje) como un 404 que indica que no se encontraron resultados. El 200 probablemente tiene más sentido: la solicitud se completó con éxito y no hubo problemas con la solicitud del cliente o durante el proceso del servidor. Un cuerpo puede entregar un mensaje al cliente.


Trataría ambos ejemplos ( http://example.com/restapi/deviceinfo?id=123y http://example.com/restapi/device/123/info) de la misma manera: 123es un parámetro. Ambos casos son diferentes formas de estructurar una solicitud para obtener información del dispositivo para un dispositivo con ID 123.

Primero, consideraría la autorización y autenticación. Si el usuario no tiene los permisos apropiados, devolvería un 403 o un 401 según corresponda. Aunque se llama "No autorizado", entiendo que 401 se trata más de autenticación y 403 se trata de no autorizado o permiso denegado. Sin embargo, no sería demasiado exigente aquí si solo quisieras apegarte a 403 para todos los errores de autenticación y autorización.

Entonces, me ocuparía de la identificación. Según su ejemplo, parece que es una identificación numérica. Si se proporcionara un valor no numérico, devolvería un 400. Si el parámetro pudiera ser un identificador de dispositivo válido, entonces continuaría con el procesamiento. Si hubiera otros argumentos, también se comprobarían aquí. Esperaría que el cuerpo de respuesta contenga información apropiada sobre por qué la solicitud fue incorrecta.

Si todos los parámetros fueran válidos, comenzaría a procesar la solicitud. Si el sistema o cualquier dependencia (una base de datos, un servicio de terceros, otro servicio interno) no está disponible, devolvería un código 5xx: 503 sería específico, pero un 500 también sería aceptable. En cualquier caso, devolvería un cuerpo con detalles adicionales. Tenga en cuenta que si una dependencia externa informa un Tiempo de espera de solicitud 408, me comería eso y devolvería un 500 a mi cliente, permitiendo que un cliente reciba un 408 solo si la solicitud a mi sistema expiró. Si el sistema puede completar la solicitud, devolvería un 200 y el cuerpo apropiado.

204 puede ser útil en algunos casos, pero le impide enviar un cuerpo de respuesta. Especialmente en una configuración de API, enviar un cuerpo de respuesta con información que se puede alimentar a un mecanismo de registro o informe parece ser la decisión correcta en la mayoría de los casos.

La única vez que se devolvería un 404 es si el servidor no tenía un /deviceinfopunto final o un /device/:id/infopunto final.

No consideraría que una identificación que no se encuentre sea la misma que el recurso no encontrado. El recurso es la información del dispositivo para un dispositivo en particular (en su ejemplo). Devolver un 404 significaría que el recurso (la información del dispositivo) no existe. Un 200 con un cuerpo apropiado significa que el sistema puede proporcionar información del dispositivo. Puede o no haber un dispositivo con la ID especificada.

Thomas Owens
fuente
1
@RobertHarvey Sí. No hubo errores. El hecho de que el servidor haya generado el GUID y lo haya enviado al cliente no significa que otra operación lo haya eliminado. La solicitud / respuesta fue exitosa. El comando o consulta representada por la solicitud no devolvió datos. Para mí, eso no es un fracaso. Que podría ser una excepción, pero no estoy convencido de que es digno de un 5xx.
Thomas Owens
2
Si estuviera diseñando esta API que estoy consultando, tendría que devolver 200 con un cuerpo que luego contenga algo device: 123; status: not found;. Entonces sé que la consulta funcionó y que la API me está dando información útil.
JYelton
77
@Blrfl Eso está respaldado (aunque no "probado") por la redacción de muchos sitios web de 500 páginas, generalmente algo así como "Cometimos un error e investigaremos". En mi opinión, un servidor que funciona correctamente nunca envía 500, excepto quizás en el caso de los rayos cósmicos.
mbrig
66
Http no tiene el concepto de un 'punto final', no hay distinción relevante entre una variable y el resto de la URL, y por lo tanto, tampoco descansa. Es posible que tenga un sistema de enrutamiento que coincida en una expresión regular y enrute miles de URL a una función de controlador, pero eso es un detalle de implementación, no una parte fundamental de la API. Una respuesta 200 en un get es solo para el caso cuando se recupera el recurso solicitado. En este caso, el cliente quiere una representación de un recurso que no existe, por lo que 404 es la respuesta correcta.
bdsl
8
Un sistema que funcione correctamente nunca envía una respuesta 500. Un servidor que funcione correctamente puede enviar un 500 porque si es parte de un sistema más grande y ha detectado un error interno en ese sistema más grande, por ejemplo, la base de datos está inactiva u otro dependiente del servicio web está devolviendo resultados sin sentido.
bdsl
5

Un error HTTP de la serie 500 indica un mal funcionamiento del servidor. Además de 501 Not Implementedy 505 HTTP Version Not Supported, el uso de estos códigos de error implica que volver a intentar la solicitud en un momento posterior puede tener éxito (aunque solo 503 Service Unavailablelo declara explícitamente). Idealmente, un servidor nunca debería producir uno de estos códigos, aunque la incapacidad para escribir software libre de errores y aprovisionar el servidor con recursos infinitos significa que los necesitará de vez en cuando.

Para un resultado de "objeto no existe", probablemente debería devolver 404 Not Found(cuando la solicitud es para un objeto por nombre) o 200 Successcon un cuerpo de resultado vacío (cuando busca un objeto por atributos). 204 No Contentparece tentador, pero lo usaría solo para situaciones donde la falta de un cuerpo de respuesta es el resultado esperado.

marca
fuente
1

Como cliente de su API, cuando realizo cualquiera de estas llamadas:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

Espero recuperar una (representación de) un DeviceInfoobjeto (o algún tipo particular de todos modos, ya sea un tipo formal o simplemente algo conforme a una convención documentada de "tipo de pato"). Quiero que un 200estado signifique que realmente tengo uno, y puedo seguir adelante y usarlo.

Para las API REST, pienso en los códigos de estado 400 y 500 como excepciones. Los utiliza para indicar cuándo no puede devolver una respuesta "normal" a la solicitud que ha recibido, por lo que el cliente deberá hacer algo excepcional en lugar de procesar la información que esperaba recuperar.

Esto significa, como consumidor de API, que puedo usar algún tipo de función de llamada de descanso comprobado que recupera una respuesta o arroja una excepción. Eso es genial; mi lógica normal puede ser un código de línea recta, y puedo organizar mi manejo de errores de la misma manera que lo hago en el código local. Los 404 inesperados se manifestarán como excepciones de "no se encontraron recursos" sin que tenga que hacer nada en absoluto, no como errores de "atributo faltante" cuando más tarde procese { errorMessage: "Device 123 not found" }como si fuera un DeviceInfoobjeto.

Si razona que http://example.com/restapi/deviceinfo se encuentra el punto final , y es solo el id=123que no, y devuelve 200 con un mensaje de error en el cuerpo, entonces está creando exactamente el mismo tipo de problemas de interfaz que las funciones C que podrían devolver un resultado correcto o un código de error, o métodos que indican problemas al devolver arbitrariamentenull. Es mucho mejor como usuario de su interfaz que los errores se indiquen a través de un canal "separado" de los retornos regulares. Eso también se aplica aquí, a pesar de que las respuestas HTTP 200, 404 y 500 son el mismo canal desde un punto de vista de bajo nivel. Están estandarizados y son fáciles de distinguir, por lo que mi marco de cliente REST puede activar fácilmente esos estados para convertirlos en las estructuras adecuadas en mi idioma; para hacer lo mismo con la capa JSON (donde siempre dice 200 y me da DeviceInfoun mensaje de error o un mensaje de error) Necesito incorporar algunos conocimientos de los esquemas JSON que usa.

Por lo tanto, solo use 200 cuando pueda devolver un valor válido del tipo esperado (es por eso que http://example.com/restapi/search-devices?colour=bluepuede devolver 200 con una matriz vacía si no hay dispositivos azules; una matriz vacía es una matriz válida y una respuesta sensata a la solicitud "I quisiera los detalles de todos los dispositivos azules "). Si no puede, use el código de estado no 200 más apropiado. A pesar de que "el dispositivo 123 no existe" es la respuesta correcta a "darme los detalles del dispositivo 123", y no es un error para el servidor , es una excepción para la expectativa del cliente de que volverá DeviceInfoy debería no se comunicará como una respuesta normal de "aquí está lo que pidió".

Ben
fuente
Lamentablemente, también soy cliente de esta API y no puedo cambiarla. Sin embargo, este es un gran resumen de cómo debería funcionar.
JYelton
0

Podría usar el error 422 Entidad no procesable para diferenciar de 404 no encontrado . 422 significa que el servidor comprende la solicitud pero no puede dar una respuesta adecuada. Estoy usando este código en situaciones similares.

FiNeX
fuente
44
Este artículo describe el uso de 422 con mayor detalle. No creo que este código de error sea realmente aplicable aquí.
Robert Harvey
Gracias muy útil! ¡Tendré que profundizar en este tema!
FiNeX
0

El error 500 normalmente indica que la solicitud bloqueó un programa del lado del servidor; En entornos empresariales, estos errores se tratan como un huevo en la cara y se evitan.

El error 4xx debe indicarle al programador que el punto final API (recurso) no existe. En consecuencia, una vez que se alcanza el punto final apropiado, cualquier manejo de errores desde ese punto en adelante es responsabilidad del programador de la API que debe manejarse con gracia, es decir, con un mensaje de error de una respuesta 200.

postronnim
fuente
1
Entonces, ¿estás diciendo "no uses 500 porque no estás bloqueando el servidor?"
Robert Harvey
0

Aunque el w3 señala que 404 se usa cuando no se aplica ninguna otra respuesta , ¿no sería esto para lo que sirve una respuesta 204 (Sin contenido)? La solicitud fue válida desde el punto de vista del procesamiento y el servidor procesó la solicitud y tiene un resultado. Eso es un éxito, que se inclina hacia las respuestas 2xx. No hubo contenido para esta solicitud en particular, por lo que 204 le dice al usuario que no hubo nada malo en su consulta, pero que no hay nada allí.

También podría hacer un caso débil de que 409 (Conflicto) es una respuesta apropiada. Aunque 409 se usa con mayor frecuencia para una POST, sí dice

La solicitud no se pudo completar debido a un conflicto con el estado actual del recurso. Este código solo se permite en situaciones en las que se espera que el usuario pueda resolver el conflicto y volver a enviar la solicitud. El cuerpo de respuesta DEBE incluir suficiente información para que el usuario reconozca la fuente del conflicto. Idealmente, la entidad de respuesta incluiría suficiente información para que el usuario o agente de usuario solucione el problema; sin embargo, eso podría no ser posible y no es obligatorio.

podría decirse que la no existencia de la identificación solicitada es el conflicto aquí, y devolver el mensaje de que dicha identificación no existe en el sistema es suficiente información para que el usuario reconozca y solucione el conflicto.

Moneyt
fuente
3
No, la respuesta 204 en una solicitud de obtención solo tendría sentido cuando se haya encontrado el recurso solicitado y su representación tenga exactamente cero caracteres de longitud.
bdsl
0

Las otras respuestas lo cubren, pero solo quería señalar que un error de la serie 500 significa "Me equivoqué". En este caso, "I" significa la API, por lo que se trata de un error del servidor no controlado o similar. Un error de la serie 400 significa "te equivocaste": la persona que llamó a la API envió algo incorrecto.

Marcie
fuente
-4

Otros usuarios han proporcionado respuestas válidas sobre qué hacer si desea seguir el libro.

Sin embargo, sugeriría que esté leyendo demasiado sobre RESTfulness y que sea absolutamente kosher con respecto a él.

REST es un protocolo caprichoso, porque si quieres seguir el libro mientras lo usas, obliga a que tanto el cliente como el servidor se construyan teniendo un conocimiento específico del hecho de que se están comunicando a través de REST, por lo que, en esencia, el protocolo de comunicación específico es usado no se puede extraer.

Hay un enfoque diferente: evitar por completo RESTfulness, y usarlo solo como un protocolo de comunicación y nada más. Esto significa que las únicas respuestas que deben devolverse son "HTTP 200 OK" y "HTTP 500 Internal Server Error" porque, en lo que respecta al protocolo de comunicación, cualquier intento de comunicación solo puede tener dos resultados: la solicitud fue exitosa entregado al servidor, o no.

Lo que sucede después de la entrega no es asunto del protocolo de comunicación. Por lo tanto, una vez que el servidor ha recibido la solicitud con éxito y comienza a procesarla, pueden producirse muchos errores, pero todos estos son errores específicos de la aplicación que no es asunto del protocolo de comunicación. Deben comunicarse dentro de la carga útil de una respuesta que parece perfectamente exitosa hasta donde el protocolo de comunicación lo sabe.

Entonces, la conclusión es que recomendaría devolver un "HTTP 200 OK" y dentro de la carga útil de respuesta ("cuerpo de contenido de respuesta" en lenguaje HTTP) tener un código de error específico de la aplicación que dice "ID no encontrado" o lo que sea.

Mike Nakis
fuente
A juzgar por los votos negativos, creo que debo haber herido los sentimientos de algunas personas. O tal vez alguna otra parte de su cuerpo. C -: =
Mike Nakis
Realmente deberían leer esto: blogs.dropbox.com/developers/2015/04/…
Mike Nakis
1
No duele aquí. Estás equivocado Incluso el artículo al que se vinculó no menciona el uso de códigos de estado tan descaradamente erróneos que los errores y el éxito se ven igual. Dice: "Hablando de gustos, es importante recordar que el diseño de la API no se trata estrictamente de las implicaciones prácticas en el software del cliente y del servidor. La audiencia de una API es el desarrollador que la va a consumir. Según el" principio de lo menos asombro ", a los desarrolladores les resultará más fácil aprender y comprender una API si sigue las mismas convenciones que otras API con las que están familiarizados".
cHao
@ cHao entonces, supongo que la parte que dice "Dropbox actualmente usa alrededor de 10 códigos de estado diferentes (8 errores y 2 para el éxito), pero estamos planeando reducir ese número en una versión futura de la API" no significaba nada tú.
Mike Nakis
No quiso decir lo que estás obteniendo de eso. Si saben lo que están haciendo, en el extremo, lo reducirían a un éxito y cuatro códigos de error (400, 401, 404 y 500), porque obviamente se preocupan por las convenciones.
cHao