REST, DELETE HTTP y parámetros

135

¿Hay algo que no sea RESTful sobre proporcionar parámetros a una solicitud HTTP DELETE?


Mi escenario es que estoy modelando el mensaje "¿Estás seguro de que quieres eliminar eso?" guión. En algunos casos, el estado del recurso sugiere que la eliminación solicitada puede no ser válida. Probablemente pueda imaginar algunos escenarios en los que se requiere la confirmación de una eliminación

La solución que hemos adoptado es pasar un parámetro a la solicitud de eliminación para indicar que está bien continuar con la eliminación ("? Force_delete = true")

p.ej

DELETE http://server/resource/id?force_delete=true

Creo que todavía es tranquilo ya que:

(a) La semántica de DELETE no se está cambiando: el usuario aún puede enviar una solicitud DELETE normal, pero esto puede fallar con 409 y el cuerpo de la respuesta explicará por qué. Digo que puede fallar porque (por razones que no vale la pena explicar) en algunas ocasiones no hay razón para avisar al usuario.

(b) No hay nada en la disertación de Roy que sugiera que está en contra del espíritu de REST: ¿por qué habría de existir ya que HTTP es solo una implementación de REST? ¿Por qué sería importante pasar los parámetros HTTP?


¿Alguien puede señalarme una declaración definitiva que explique la razón por la cual esto no es RESTful?

En una pregunta relacionada, si el usuario no especifica force_delete, entonces estoy regresando 409 Conflict: ¿es ese el código de respuesta más apropiado?


Seguimiento

Después de algunas investigaciones adicionales, creo que agregar parámetros a DELETE puede violar varios principios.

La primera es que la implementación posiblemente viola la "Interfaz Uniforme" (ver sección 5.1.5 de la disertación de Roy

Al agregar 'force_delete' estamos agregando una restricción adicional al método DELETE ya bien definido. Esta restricción es significativa solo para nosotros.

También podría argumentar que viola el "5.1.2 Cliente-Servidor" ya que el diálogo de confirmación es realmente una preocupación de UI y nuevamente no todos los clientes querrán confirmar la eliminación.

Sugerencias a alguien?

Chris McCauley
fuente
1
Su url para la disertación de Roy contiene un ")" que causa un 404. ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm funciona.
NuclearPeon

Respuestas:

78

No, no es RESTful. La única razón por la que debería poner un verbo ( force_delete) en el URI es si necesita sobrecargar los métodos GET / POST en un entorno donde los métodos PUT / DELETE no están disponibles. A juzgar por su uso del método DELETE, este no es el caso.

El código de error HTTP 409/Conflictdebe usarse para situaciones en las que existe un conflicto que impide que el servicio RESTful realice la operación, pero aún existe la posibilidad de que el usuario pueda resolver el conflicto él mismo. Una confirmación previa a la eliminación (donde no hay conflictos reales que impidan la eliminación) no es un conflicto per se, ya que nada impide que la API realice la operación solicitada.

Como dijo Alex (no sé quién lo rechazó, él tiene razón), esto debe manejarse en la interfaz de usuario, porque un servicio RESTful como tal solo procesa solicitudes y, por lo tanto, no debe tener estado (es decir, no debe basarse en las confirmaciones manteniendo cualquier información del lado del servidor sobre una solicitud).

Dos ejemplos de cómo hacer esto en la interfaz de usuario serían:

  • pre-HTML5 : * muestra un diálogo de confirmación JS al usuario y envía la solicitud solo si el usuario lo confirma
  • HTML5 : * use un formulario con la acción ELIMINAR donde el formulario contendrá solo los botones "Confirmar" y "Cancelar" ("Confirmar" sería el botón de enviar)

(*) Tenga en cuenta que las versiones HTML anteriores a la 5 no son compatibles con los métodos HTTP PUT y DELETE, sin embargo, la mayoría de los navegadores modernos pueden hacer estos dos métodos a través de llamadas AJAX. Consulte este hilo para obtener detalles sobre la compatibilidad entre navegadores.


Actualización (basada en investigaciones y discusiones adicionales):

El escenario donde el servicio requeriría que la force_delete=truebandera esté presente viola la interfaz uniforme como se define en la disertación de Roy Fielding. Además, de acuerdo con HTTP RFC , el método DELETE puede anularse en el servidor de origen (cliente), lo que implica que esto no se hace en el servidor (servicio) de destino.

Por lo tanto, una vez que el servicio recibe una solicitud DELETE, debe procesarla sin necesidad de confirmación adicional (independientemente de si el servicio realmente realiza la operación).

Ratones
fuente
2
¿Podría explicar qué restricción REST se está violando? Teniendo en cuenta que los URI deben ser opacos para el cliente, ¿por qué cree que las expectativas del cliente no se están cumpliendo con el uso de un DELETE HTTP que elimina un recurso pero no elimina otro? No estoy seguro de que 409 sea el mejor código de estado para devolver, pero además de ser una implementación un poco extraña, no puedo encontrar ninguna restricción REST que se esté rompiendo.
Darrel Miller
2
@Darrel: (en mi humilde opinión) viola la interfaz uniforme por el método DELETE que no funciona según los estándares HTTP. Considere un cliente REST que asume un servicio REST estándar: ¿cómo le hará saber al cliente que necesita agregarlo force_delete=true? De acuerdo con HTTP RFC, el método DELETE puede ser anulado en el servidor de origen (cliente), lo que implica que esto no se hace en el servidor (servicio) de destino. Entonces, entiendo que una vez que el servicio recibe una solicitud DELETE, debe procesarla sin necesidad de confirmación (independientemente de si el servicio realmente realiza la operación).
MicE
1
@ Chris, a su segundo punto: sí, eso también lo entiendo, es decir, que el estado sugiere un conflicto real y no una necesidad de confirmación. Acabo de notar la actualización que hiciste en tu pregunta, y estoy de acuerdo: mientras lo estaba investigando, llegué a la misma conclusión (que esto viola la interfaz uniforme y que la confirmación debe hacerse en el cliente / UI lado). También me encontré con un hilo muy interesante aquí, podría ayudar: mail-archive.com/[email protected]/msg13578.html
MicE
2
@MicE En gran medida, estoy de acuerdo con usted en que no es la forma ideal de manejar este escenario. Solo estoy siendo un poco exigente con la etiqueta "no es RESTful". Por un tiempo aquí, esa frase fue lanzada a todo. Sin embargo, sería posible definir reglas para un tipo de medio que diga si intenta BORRAR un recurso y obtiene un error (diría que 403 prohibido sería mejor que 409), entonces el cliente debería intentar BORRAR en un recurso relacionado añadiendo un "force_delete = true". En cierto modo, es un poco como la autorización. OBTENGA, obtenga 401, agregue el encabezado de autenticación y OBTENGA nuevamente.
Darrel Miller
2
@Darrel: ese es un muy buen punto, gracias. Y he visto a personas lanzar la etiqueta de no RESTful yo mismo. Es posible que hoy en día la barrera entre los servicios y las aplicaciones web se esté volviendo muy nebulosa, por lo que un grupo de personas puede ver esto desde un punto de vista de servicio puro, mientras que otros lo ven desde un punto de vista mixto de aplicación / servicio. Creo que es donde entra en juego la verdadera pregunta sobre cómo hacer la confirmación. @ Chris: actualizado - ¡gracias señor por un tema y discusión muy interesante!
MicE
35

Creo que esto no es tranquilo. No creo que el servicio reparador deba manejar el requisito de obligar al usuario a confirmar una eliminación. Me ocuparía de esto en la interfaz de usuario.

¿Tiene sentido especificar force_delete = true si esta fuera la API de un programa? Si alguien escribiera un script para eliminar este recurso, ¿desearía obligarlo a especificar force_delete = true para eliminar realmente el recurso?

Alex Rockwell
fuente
El primer párrafo de su respuesta es su opinión y lo respeto, pero no ha señalado algo en la literatura que prohíba el uso del URI como este: todavía identifica el recurso y se está utilizando el verbo HTTP más apropiado. En respuesta a tus preguntas; Sí, todavía tendría sentido (en mi opinión). Esperaría que un script (tal vez basado en CURL) respete la respuesta 409 y sugiera al usuario cómo se puede reenviar la solicitud, todo basado en mi cuerpo de respuesta
Chris McCauley
Buen punto sobre la comparación de la API web con la API de un programa. Esa suele ser una buena manera de averiguar si una API es RESTful o no.
Laurent
18

Es una vieja pregunta, pero aquí hay algunos comentarios ...

  1. En SQL, el comando DELETE acepta un parámetro "CASCADE", que le permite especificar que también se eliminen los objetos dependientes. Este es un ejemplo de un parámetro DELETE que tiene sentido, pero 'man rm' podría proporcionar otros. ¿Cómo se podrían implementar estos casos en REST / HTTP sin un parámetro?
  2. @ Jan, parece ser una convención bien establecida que la parte de ruta de la URL identifica un recurso, mientras que la cadena de consulta no lo hace (al menos no necesariamente). Abundan los ejemplos: obtener el mismo recurso pero en un formato diferente, obtener campos específicos de un recurso, etc. Si consideramos la cadena de consulta como parte del identificador del recurso, es imposible tener un concepto de "diferentes vistas del mismo recurso" sin recurrir a mecanismos no RESTful como la negociación de contenido HTTP (que puede ser indeseable por muchas razones).
Shay Rojansky
fuente
Gracias por agregar esto a la conversación, incluso si no es una gran conversación ya que dura años.
silviot
6

Además de la respuesta de Alex:

Tenga en cuenta que http: // server / resource / id? Force_delete = true identifica un recurso diferente que http: // server / resource / id . Por ejemplo, es una gran diferencia si elimina / clients /? Status = old o / clients /.

ene

Jan Algermissen
fuente
No estoy de acuerdo, soy libre de proporcionar múltiples URI para identificar el mismo recurso.
Chris McCauley
18
Sí, todos son libres de hacer un desastre :-)
Jan Algermissen
La indicación de URI canónicos podría ayudar con esto: googlewebmastercentral.blogspot.com/2009/02/…
MicE
@Chris Solo debe haber un URI que devuelva una representación de un recurso. Otros URI pueden referirse al mismo concepto, pero hacer un GET debería devolver un 303 Ver otro. Y solo para contrarrestar la obvia objeción a esto, /foo.xml y /foo.json son dos recursos diferentes.
Darrel Miller
@Darrell: de acuerdo, pero el formato no es un problema aquí. Además, el formato es una convención en Rails y otros marcos que no forman parte de REST: debe utilizar la negociación de contenido en HTTP con MIME o microformatos para implementarlo completamente.
Chris McCauley