¿Qué verbo HTTP debo usar para activar una acción en un servicio web REST?

81

Estoy implementando un servicio web RESTful y una de las acciones disponibles será reload. Se usará para recargar configuraciones, caché, etc.

Comenzamos con un simple GETa un URI como este: ${path}/cache/reload(no se pasan parámetros, solo se llama el URI). Soy consciente de que los datos no deben modificarse con una solicitud GET.

¿Cuál es el verbo correcto para invocar una acción / comando en un servicio web RESTful?

La recarga es un comando del servicio web REST que recarga su propia caché / configuración / etc. No es un método que devuelve información al cliente.

Probablemente lo que estoy tratando de hacer no es DESCANSAR, pero todavía es algo que debe hacerse de esta manera. El reloadmétodo fue solo un ejemplo real que tiene sentido en el alcance de la aplicación y la mayoría de las respuestas se centraron en él, pero de hecho, solo necesitaba saber qué verbo desencadenar una acción que no hace CRUD, pero que todavía cambia los datos / estado.

Encontré esta respuesta detallada en Stack Overflow sobre el tema: https://stackoverflow.com/questions/16877968/

Renato Dinhani
fuente
1
¿"Recargar" es el sentido de una aplicación que actualiza los datos que va a mostrar? ¿Hay alguna diferencia entre recargar y volver a obtener los datos?
Sean Redmond el
1
@SeanRedmond No, los datos no se envían al cliente. De hecho, es el cliente quien le dice al servicio web REST que ejecute un comando interno (recargar). Algo así como: "se cambiaron muchas configuraciones en la base de datos, por lo que el servicio web REST, vuelva a cargarlas en su memoria ahora".
Renato Dinhani
Duplicado entre sitios: stackoverflow.com/q/15340946/319403
cHao
¿Ha considerado usar un parámetro de encabezado en las solicitudes apropiadas? Esto suena muy parecido a una actualización de caché ...
Guran

Respuestas:

25

No creo que haya un verbo apropiado para esta acción porque esta transacción no es realmente "RESTful". La "s" y la "t" significan "transferencia de estado" y aquí no se transfiere nada. O, dicho de otra manera, según la definición más estricta, los verbos como PUT y POST siempre se usan con un sustantivo y "reload" solo tiene el verbo.

Es posible que esta recarga no sea RESTful, pero aún puede ser útil y solo tendrá que elegir una forma de hacerlo y vivir o explicar que es inusual. GET es probablemente el más simple. Sin embargo, hay una gran cantidad de escepticismo en los comentarios, por lo que debe pensar si esta acción de recarga es necesaria o no porque algo más no está haciendo lo que debería estar haciendo.

Sean Redmond
fuente
Estoy de acuerdo en que esto no es RESTful pero puede ser útil. Sin embargo, creo que debería aconsejar un PUT, porque probablemente sea idempotente pero no nuloimpotente.
Aaron Greenwald el
@ Aaron, la comparación de idempotente y nullimpotente está muy bien, pero ¿cómo se determina cuándo no es tan potente?
Craig
@Craig es idempotente si ejecutarlo muchas veces tiene el mismo efecto que ejecutarlo una vez. Es nipipotente si ejecutarlo una o varias veces tiene el mismo efecto en el servidor que ejecutarlo cero veces. en.wikipedia.org/wiki/Idempotence
Aaron Greenwald
55
@AaronGreenwald "notimpotente" [not-im-poht-nt] [not-im-pawr-tnt] - adjetivo - 1. Un juego de palabras, "no importante", antónimo del adjetivo "importante" 2. Humor ... ;-)
Craig
@Craig, me lo perdí por completo :)
Aaron Greenwald
75

Si quiere RESTAR, no piense en el verbo para llevar a cabo una acción, piense en el estado en el que desea que esté el recurso después de que el cliente haya hecho algo.

Entonces, utilizando uno de los ejemplos anteriores, tiene una cola de correo electrónico que envía correos electrónicos. Desea que el cliente ponga esa cola de correo electrónico en el estado de pausa o detenido o algo así.

Entonces el cliente PONE un nuevo estado al servidor para ese recurso. Puede ser tan simple como este JSON

PUT http://myserver.com/services/email_service HTTP/1.1
Content-Type: text/json

{"status":"paused"}

El servidor descubre cómo pasar del estado actual (por ejemplo, "en ejecución") al estado / estado "en pausa".

Si el cliente realiza un GET en el recurso, debería devolver el estado en el que se encuentra actualmente (por ejemplo, "en pausa").

La razón para hacerlo de esta manera, y por qué REST puede ser tan poderoso, es que abandonas el CÓMO para llegar a ese estado en el servidor.

El cliente simplemente dice "Este es el estado en el que debería estar ahora" y el servidor descubre cómo lograrlo. Puede ser un simple cambio en una base de datos. Puede requerir miles de acciones. Al cliente no le importa y no tiene que saberlo.

Entonces puede reescribir / rediseñar por completo cómo lo hace el servidor y al cliente no le importa. El cliente solo necesita conocer los diferentes estados (y sus representaciones) de un recurso, no ninguno de los componentes internos.

Cormac Mulhall
fuente
2
En lo que a mí respecta, esta es la respuesta correcta. Actualizar datos en el servidor no es una operación idempotente, y GETes un verbo completamente inapropiado para usar. PUTes el verbo más apropiado, ya que se puede considerar que la operación actualiza el "estado recargado" de la memoria caché a "recargado".
Jez
@Jez De las respuestas aquí, prefiero esta también. Siguiendo con la metáfora de correo electrónico, de improviso que no se siente extraño al principio de pensar en enviar el correo poniéndolo en el estado "enviar" en lugar de sólo el envío de él (una acción). Pero si lo piensas, eso es realmente lo mismo que ponerlo en la "bandeja de salida". De hecho, el sistema de correo en sí mismo probablemente lo está haciendo cola internamente cuando le dice que envíe. Por lo tanto, la API puede permitirle poner el correo en el estado de "envío", y la API no está obligada a explicarse más allá de eso.
Craig
Entonces, por extensión, si aún no desea que el mensaje se envíe, póngalo en el estado "programado" con una fecha / hora en la que debería publicarse. Si no está completo, lo coloca (o está implícitamente / por defecto) en el estado "borrador", etc.
Craig
... aunque creo que preferiría POST a PUT en este caso, ya que también se supone que PUT es idempotente, pero POST no tiene esa restricción.
Craig
1
Podrías hacer eso, pero en última instancia está tratando de encajar una clavija cuadrada en un agujero redondo. No hay ninguna razón por la cual el cliente necesita activar el servidor para "recargar" algo, eso es simplemente un diseño arquitectónico deficiente. El servidor puede actualizar su estado interno en cada llamada o en un intervalo de tiempo fijo. Confiar en el cliente para decirle al servidor que vuelva a cargar algo independiente de cualquier solicitud real de un estado de recurso no es una arquitectura RESTful.
Cormac Mulhall
32

Algunas de las otras respuestas, incluida la aceptada, le aconsejan que use un GET (aunque no con mucho entusiasmo).

Estoy en desacuerdo.

En primer lugar, todos los demás que le dicen que esto no es ideal y que no es realmente RESTful son correctos. En un escenario RESTful adecuado, está manipulando recursos en el servidor y agregando, actualizando, eliminando, recuperando, etc. esos recursos. Un PUT debe enviar una carga útil que represente cuál debe ser el recurso cuando se complete la solicitud, y POST debe enviar una carga útil que represente un recurso que se agregará al servidor. Y un GET debería devolver un recurso en el servidor.

Tiene una RPC (llamada a procedimiento remoto), que no es RESTful; desea hacer algo en el servidor. Entonces, si está tratando de crear una API RESTful puramente, debería reconsiderar lo que está haciendo.

Dicho esto, a veces necesitas doblar un poco las reglas. Especialmente si está desarrollando una API interna que no va a estar expuesta al público, puede decidir que la compensación vale la pena.

Si lo hace, recomendaría un PUT o POST, dependiendo de si el RPC es idempotente o no.

En general, decimos que HTTP PUT se asigna a SQL UPDATE y que HTTP POST se asigna a SQL INSERT, pero eso no es estrictamente cierto. Una forma más pura de afirmar que es que HTTP PUT debe ser idempotente y HTTP POST no tiene por qué serlo. Esto significa que puede llamar a la misma solicitud PUT tantas veces como desee sin efectos secundarios. Una vez que lo haya llamado una vez, es inofensivo volver a llamarlo. Pero no debe llamar repetidamente a las solicitudes POST a menos que lo desee: cada POST cambia los datos en el servidor nuevamente.

En su caso, si necesita tener esta función de recarga, recomendaría un PUT porque parece que es idempotente. Pero aun así, le insto a que considere lo que dijeron los demás sobre no necesitarlo en absoluto.

Aaron Greenwald
fuente
6

POSTy PUTson los verbos HTTP utilizados para enviar una entidad a un servidor web. Con PUT, la entidad enviada es la representación (nueva) para el recurso en el URI dado, que no se ajusta a lo que desea. POSTes para el controlador de formulario tradicional, donde la entidad es información auxiliar para el recurso, por lo que es el ganador. La entidad incluiría el comando o acción (por ejemplo, "acción = recargar").

Dicho esto, el comando en cuestión probablemente no debería exponerse a través de una interfaz REST. Parece que surge la necesidad de "recargar" porque los datos se pueden cambiar a través de algún otro canal (por ejemplo, sistema de archivos, cliente DB). Los cachés deben ser transparentes. Además, las solicitudes HTTP deben ser atómicas, incluso teniendo en cuenta los mensajes enviados a través de otros canales. Ofrecer un comando "recargar" para los ajustes de configuración parece una complejidad innecesaria; exigirlo es un diseño quebradizo. Exponer "recargar" a la limpieza después de una actualización a través de otro canal está sucio porque un canal no contiene toda la conversación. En cambio, considere uno de:

  • haciendo actualizaciones completamente a través de REST
  • exponiendo los comandos al otro canal
  • automatizando las acciones

Algunas de esas opciones pueden no ser viables, dependiendo de qué otras restricciones existan.

Ver también " PUT vs POST in REST ".

outis
fuente
Gracias. Eliminé el "interno" de la edición porque, de hecho, el método de "recarga" está destinado a ser público. Solo intenté decir que se refiere al servicio web en sí. Creo que publicar la "acción" sería un buen enfoque.
Renato Dinhani
@ RenatoDinhaniConceição: incluso sin el "interno", todavía huele. Puede que le incumba hacer una nueva pregunta sobre si el diseño es bueno.
outis
4

Argumentaría por qué una solicitud de un cliente necesitaría explícitamente hacer una llamada para actualizar algo así. Parece que eso debería ser una lógica oculta en una implementación más típica de GET (es decir, datos de extracción, pero el servicio actualiza los datos antes de extraerlos) o mediante otro desencadenante en el back-end lejos del cliente.

Después de todo, los datos / configuración solo tendrían que estar actualizados en las llamadas posteriores, por lo que me inclinaría más hacia una llamada perezosa frente a una ansiosa para una actualización de datos. Obviamente estoy asumiendo mucho aquí, pero daría un paso atrás para reevaluar la necesidad de una llamada tan explícita e independiente.

Thomas Stringer
fuente
Mira mi edición. "recargar" no es un comando que devuelve datos. Se refiere al servicio web REST en sí. En términos generales, mi pregunta se refiere a la activación de acciones en un servicio web REST. Otro ejemplo puede ser: email_queue/stop_sending_emails. Estoy justificando dar un comando a algo usando una interfaz RESTful.
Renato Dinhani el
55
Aún estoy de acuerdo. Invocar SIGHUP en un proceso local tiene sentido, ya que la computadora debe confiar en alguien conectado localmente que tiene acceso a esa señal. ¿Pero para un protocolo apátrida y accesible por Internet? Quizás el servicio web debería recargarse automáticamente según sea necesario a través de encuestas o monitoreo de archivos. Esta llamada debería ser completamente innecesaria.
1
Estoy de acuerdo. Cosas como la configuración y el almacenamiento en caché deben ser transparentes para el cliente. Tal vez debería darnos una descripción más concreta de una situación en la que se llamaría a su punto final.
Benjamin Hodgson el
3

¿Por qué no tratar la acción como un recurso? Entonces, dado que desea actualizar el caché, PUBLICARÍA una nueva acción en su sistema.

Para los puristas, podría tener una URL dedicada para eso. Tenga en cuenta que puede extender esto y registrar las acciones reales en una base de datos (o cualquier almacenamiento) con fecha, estado, usuario, etc. Solo mis pensamientos aquí.

Operación genérica en todo el sistema / acciones / {acción}

Operación específica para un tipo de recurso / acciones / {recurso} / {acción}

Operación específica de un recurso / acciones / {recurso} / {id} / {acción}

En su caso, el caché probablemente esté en todo el sistema / actions / reload_cache

Isometriq
fuente
0

¿Qué verbo HTTP debo usar para activar una acción en un servicio web REST?

Al considerar los detalles de un servicio REST, a menudo es útil considerar esta heurística: ¿cómo implementaría esto con un sitio web?

HTML solo puede describir de forma nativa las solicitudes GET y POST. Entonces podemos comenzar a buscar allí.

Es GETapropiado? Para responder a esta pregunta, debemos pensar en los supuestos que los clientes y los componentes intermedios tienen permitido hacer GET. La semántica de GETson seguras

el cliente no solicita, y no espera, ningún cambio de estado en el servidor de origen como resultado de aplicar un método seguro a un recurso de destino. Del mismo modo, no se espera que el uso razonable de un método seguro cause ningún daño, pérdida de propiedad o carga inusual en el servidor de origen.

La implicación, por lo tanto, es que los clientes y los componentes intermedios tienen discreción para invocar una solicitud GET con la frecuencia necesaria para satisfacer sus propias preocupaciones. Las arañas pueden OBTENER recursos indiscriminadamente para actualizar sus índices. Los cachés pueden pretraerse. En una red poco confiable, los mensajes perdidos se pueden volver a consultar con la frecuencia necesaria para garantizar al menos una respuesta.

Se usará para recargar configuraciones, caché, etc.

Si se trata de algo costoso, tal vez no desee que los clientes emitan estas solicitudes a su propia discreción.

POST, por otro lado, no tiene restricciones, esto reduce en gran medida las suposiciones que los clientes genéricos pueden hacer. No obtienes componentes que hacen solicitudes POST especulativas porque sería incorrecto hacerlo; nada en el estándar dice que está bien.

PUT, PATCH, DELETE... estos son métodos inseguros con semántica más específicos que POST; si son apropiados o no dependerá de su modelo de recursos.

Una idea importante a tener en cuenta es que los métodos HTTP pertenecen al dominio del documento (consulte la charla de Jim Webber de 2011 ), los efectos que está describiendo probablemente no formen parte del dominio del documento, sino que son efectos secundarios que se invocan cuando se cambian los documentos. . Eso le da mucha libertad en términos de cómo organizar sus documentos para realizar el trabajo.

VoiceOfUnreason
fuente