Quel verbe HTTP dois-je utiliser pour déclencher une action dans un service Web REST?

81

J'implémente un service Web RESTful et l'une des actions disponibles sera reload. Il sera utilisé pour recharger les configurations, le cache, etc.

Nous avons commencé avec un simple GETà un URI comme ceci: ${path}/cache/reload(aucun paramètre n'est passé, seul l'URI est appelé). Je suis conscient que les données ne doivent pas être modifiées avec une demande GET.

Quel est le verbe correct à utiliser pour appeler une action / commande dans un service Web RESTful?

Le rechargement est une commande du service Web REST qui recharge son propre cache / configuration / etc. Ce n'est pas une méthode qui renvoie des informations au client.

Probablement ce que j'essaie de faire n'est pas REST, mais c'est toujours quelque chose qui doit être fait de cette façon. La reloadméthode n'était qu'un exemple concret qui avait du sens dans le champ d'application et sur laquelle la plupart des réponses étaient centrées, mais en fait, je voulais juste savoir quel verbe déclencher une action qui ne fait pas CRUD, mais modifie encore les données / Etat.

J'ai trouvé cette réponse détaillée sur Stack Overflow sur le sujet: https://stackoverflow.com/questions/16877968/

Renato Dinhani
la source
1
"Recharger" signifie-t-il qu'une application rafraîchit les données qu'elle va afficher? Existe-t-il une différence entre recharger et simplement récupérer les données?
Sean Redmond
1
@SeanRedmond Non, les données ne sont pas envoyées au client. En fait, le client demande-t-il au service Web REST d’exécuter et à une commande interne (recharger). Quelque chose comme: "beaucoup de configurations ont été modifiées dans la base de données, le service Web REST doit donc les recharger dans votre mémoire maintenant".
Renato Dinhani
Double sur plusieurs
Avez-vous envisagé d'utiliser un paramètre d'en-tête sur les demandes appropriées? Cela ressemble beaucoup à un rafraîchissement de cache ...
Guran

Réponses:

25

Je ne pense pas qu'il existe un verbe approprié pour cette action car cette transaction n'est pas vraiment "RESTful". Le "s" et le "t" signifient "transfert d'état" et rien n'est transféré ici. Autrement dit, selon la définition la plus stricte, les verbes comme PUT et POST sont toujours utilisés avec un nom et "reload" a juste le verbe.

Ce rechargement peut ne pas être RESTful, mais il peut toujours être utile et vous devrez simplement choisir un moyen de le faire et vivre avec ou expliquer que c'est inhabituel. GET est probablement le plus simple. Les commentaires sont toutefois assez sceptiques. Vous devez donc vous demander si cette opération de rechargement est nécessaire ou non, car une autre action ne fait pas tout à fait ce qu'elle devrait être.

Sean Redmond
la source
Je conviens que ce n'est pas RESTful mais peut être utile. Je pense que vous devriez cependant conseiller un PUT, parce que c'est probablement idempotent mais pas nullimpotent.
Aaron Greenwald
@Aaron, la comparaison entre idempotent et nullimpotent est très bien, mais comment déterminez-vous quand ce n'est pas impotent?
Craig
@Craig est idempotent si le lancer à plusieurs reprises a le même effet que de le lancer une fois. Il est nullipotent si son exécution une ou plusieurs fois a le même effet sur le serveur que son exécution zéro fois. en.wikipedia.org/wiki/Idempotence
Aaron Greenwald
5
@AaronGreenwald “non impotent” [non-im-poht-nt] [non-im-pawr-tnt] - adjectif - 1. Un jeu de mots, “pas important”, terme opposé de l'adjectif “important”. 2. Humour… ;-)
Craig
@Craig, j'ai complètement raté ça :)
Aaron Greenwald
75

Si vous voulez être RESTful, ne pensez pas au verbe pour exécuter une action, pensez à l' état dans lequel vous voulez que la ressource soit après que le client a fait quelque chose.

Donc, en utilisant l’un des exemples ci-dessus, vous avez une file d’envoi de courriels. Vous souhaitez que le client mette cette file d'attente de messages dans l'état arrêté ou arrêté.

Donc, le client PUT un nouvel état sur le serveur pour cette ressource. Cela peut être aussi simple que ce JSON

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

{"status":"paused"}

Le serveur détermine comment passer de l'état actuel (par exemple "en cours d'exécution") à l'état "en pause".

Si le client effectue une opération GET sur la ressource, il doit retourner l'état dans lequel il se trouve actuellement (par exemple, "en pause").

La raison de le faire de cette façon, et pourquoi REST peut être si puissant, est que vous quittez le mode COMMENT accéder à cet état sur le serveur.

Le client dit simplement "Ceci est l'état dans lequel vous devriez être maintenant" et le serveur détermine comment y parvenir. Ce pourrait être un simple retournement dans une base de données. Cela pourrait nécessiter des milliers d'actions. Le client s'en fiche et n'a pas à savoir.

Ainsi, vous pouvez complètement réécrire / redessiner comment le serveur fait cela et le client ne s'en soucie pas. Le client doit uniquement connaître les différents états (et leurs représentations) d’une ressource, et non l’un des éléments internes.

Cormac Mulhall
la source
2
En ce qui me concerne, c'est la bonne réponse. L'actualisation des données sur le serveur n'est pas une opération idempotente et GETconstitue un verbe totalement inapproprié à utiliser. PUTest le verbe le plus approprié car l'opération peut être considérée comme une mise à jour du "statut rechargé" du cache sur "rechargé".
Jez
@Jez Parmi les réponses ici, je préfère celle-ci aussi. Si on s'en tient à la métaphore de l'e-mail, il est bizarre au début de penser envoyer le courrier en le mettant dans l'état "envoi" au lieu de l' envoyer simplement (une action). Mais si vous y réfléchissez, c'est vraiment la même chose que de le mettre dans la "boîte d'envoi". En fait, le système de messagerie lui-même le met probablement en file d'attente de cette manière en interne lorsque vous lui indiquez d'envoyer. Ainsi, l'API peut vous permettre de mettre le courrier dans l'état "envoi", et l'API n'est pas obligée de s'expliquer au-delà.
Craig
Donc, par extension, si vous ne voulez pas que le message soit envoyé pour l'instant, vous le mettez dans l'état "programmé" avec une date / heure à laquelle il doit être publié. Si ce n'est pas complet, vous le mettez (ou c'est implicitement / par défaut) dans l'état "brouillon", etc.
Craig
... bien que je pense que je préférerais POST à ​​PUT dans ce cas, puisque PUT est également supposé être idempotent, mais POST n'est pas soumis à une telle contrainte.
Craig
1
Vous pouvez le faire, mais au final, vous essayez d’insérer une cheville carrée dans un trou rond. Il n’ya aucune raison pour que le client demande au serveur de "recharger" quoi que ce soit, c’est simplement une mauvaise conception architecturale. Le serveur peut mettre à jour son état interne à chaque appel ou à un intervalle de temps fixe. Compter sur le client pour demander au serveur de recharger quelque chose indépendamment de toute demande réelle pour un état de ressource n'est pas une architecture RESTful.
Cormac Mulhall
32

Certaines des autres réponses, y compris celle acceptée, vous conseillent d’utiliser un GET (bien que pas très enthousiaste).

Je ne suis pas d'accord.

Tout d'abord, tous les autres qui vous disent que ce n'est pas idéal et pas vraiment reposant sont corrects. Dans un scénario RESTful approprié, vous manipulez des ressources sur le serveur et ajoutez, mettez à jour, suppriment, récupérez, etc. ces ressources. Un PUT doit envoyer une charge utile qui représente la ressource lorsque la demande est terminée, et POST doit envoyer une charge utile représentant une ressource à ajouter au serveur. Et un GET devrait renvoyer une ressource sur le serveur.

Vous avez un appel de procédure distante (RPC), qui n'est pas RESTful - vous voulez faire quelque chose sur le serveur. Donc, si vous essayez de créer une API purement RESTful, vous devriez reconsidérer votre travail.

Cela dit, il est parfois nécessaire de contourner un peu les règles. Surtout si vous développez une API interne qui ne sera pas exposée au public, vous pouvez décider que le compromis en vaut la peine.

Si vous le faites, je recommanderais un PUT ou un POST, selon que le RPC est idempotent ou non.

En général, on dit que HTTP PUT mappe vers SQL UPDATE et que HTTP POST mappe sur SQL INSERT, mais ce n'est pas strictement vrai. Une façon plus simple de dire que HTTP PUT doit être idempotent et que HTTP POST ne doit pas l'être. Cela signifie que vous pouvez appeler la même demande PUT autant de fois que vous le souhaitez, sans effets secondaires. Une fois que vous l'avez appelé, il est inoffensif de le rappeler. Mais vous ne devez pas appeler de manière répétée les demandes POST sauf si vous le souhaitez - chaque POST modifie à nouveau les données sur le serveur.

Dans votre cas, si vous avez besoin de cette fonction de rechargement, je vous recommanderais un PUT car cela semble être idempotent. Mais je vous exhorterais néanmoins à tenir compte de ce que les autres ont dit sur le fait de ne pas en avoir besoin du tout.

Aaron Greenwald
la source
6

POSTet PUTsont les verbes HTTP utilisés pour soumettre une entité à un serveur Web. Avec PUT, l'entité soumise est la (nouvelle) représentation de la ressource à l'URI donné, ce qui ne correspond pas à ce que vous voulez. POSTest pour le gestionnaire de formulaire traditionnel, où l'entité est des données auxiliaires pour la ressource, donc c'est le gagnant. L'entité inclurait la commande ou l'action (par exemple, "action = reload").

Cela dit, la commande en question ne devrait probablement pas être exposée via une interface REST. Il semble que la nécessité de "recharger" se pose car les données peuvent être modifiées via un autre canal (système de fichiers, client DB, par exemple). Les caches doivent être transparents. De plus, les requêtes HTTP doivent être atomiques, même en tenant compte des messages envoyés via d'autres canaux. Proposer une commande "reload" pour les paramètres de configuration semble une complexité inutile. l'exiger est un design fragile. Exposer le «rechargement» au nettoyage après une mise à jour via un autre canal est sale car un canal ne contient pas toute la conversation. Au lieu de cela, considérez l'un des:

  • faire des mises à jour entièrement via REST
  • exposer la ou les commandes à l'autre canal
  • automatiser les actions

Certaines de ces options pourraient ne pas être viables, en fonction des restrictions existantes.

Voir aussi " PUT vs POST in REST ".

outis
la source
Je vous remercie. J'ai supprimé le "interne" de la modification parce qu'en fait la méthode "reload" est destinée à être publique. J'ai juste essayé de dire que cela faisait référence au service Web lui-même. Je pense que l'affichage de "l'action" serait une bonne approche.
Renato Dinhani
@ RenatoDinhaniConceição: même sans "l'interne", ça sent toujours. Il vous incombe peut-être de poser une nouvelle question pour savoir si le design est bon.
outis
4

Je dirais pourquoi une demande client aurait explicitement besoin de faire un appel pour actualiser quelque chose comme ça. Cela semble être une logique cachée dans une implémentation plus typique de GET (Ie Pull data, mais le service actualise les données avant qu’elles ne soient extraites), ou par un autre déclencheur situé à l’arrière du client.

Après tout, les données / config n'auraient besoin que d'être à jour pour les appels suivants, donc je m'approcherais plutôt d'un appel paresseux que désireux pour un rafraîchissement des données. Évidemment, je suppose beaucoup ici, mais je ferais un pas en arrière pour réévaluer la nécessité d’un appel aussi explicite et autonome.

Thomas Stringer
la source
Regardez mon édition. "reload" n'est pas une commande qui renvoie des données. Il fait référence au service Web REST lui-même. De manière générale, ma question concerne le déclenchement d’actions dans un service Web REST. Autre exemple peut être: email_queue/stop_sending_emails. Je veux juste donner une commande à quelque chose en utilisant une interface RESTful.
Renato Dinhani
5
Je suis toujours d'accord. Invoquer SIGHUP sur un processus local est logique, car l'ordinateur doit faire confiance à une personne connectée localement qui a accès à ce signal. Mais pour un protocole sans état et accessible sur Internet? Peut-être que le service Web devrait recharger automatiquement si nécessaire via une interrogation ou une surveillance de fichier. Cet appel devrait être complètement inutile.
1
Je suis d'accord. Des éléments tels que la configuration et la mise en cache sont censés être transparents pour le client. Peut-être devriez-vous nous donner une description plus concrète d'une situation dans laquelle votre point final serait appelé.
Benjamin Hodgson
3

Pourquoi ne pas traiter l'action comme une ressource. Donc, puisque vous voulez mettre à jour le cache, vous pouvez poster une nouvelle action dans votre système.

Pour les puristes, vous pouvez avoir une URL dédiée à cela. Notez que vous pouvez étendre ceci et enregistrer les actions réelles dans une base de données (ou n'importe quel stockage) avec la date, le statut, l'utilisateur, etc.

Opération générique à l'échelle du système / actions / {action}

Opération spécifique à un type de ressource / actions / {ressource} / {action}

Opération spécifique à une ressource / actions / {ressource} / {id} / {action}

Dans votre cas, le cache est probablement à l'échelle du système / actions / reload_cache

Isometriq
la source
0

Quel verbe HTTP dois-je utiliser pour déclencher une action dans un service Web REST?

Lorsque vous examinez les détails d'un service REST, il est souvent utile de prendre en compte cette heuristique: comment la mettriez-vous en œuvre avec un site Web?

HTML ne peut décrire que nativement les requêtes GET et POST. Nous pouvons donc commencer à chercher là-bas.

Est-ce GETapproprié? Pour répondre à cette question, nous devons réfléchir aux hypothèses que les clients et les composants intermédiaires sont autorisés à formuler GET. La sémantique de GETare safe

le client ne demande pas et ne s'attend à aucun changement d'état sur le serveur d'origine suite à l'application d'une méthode sécurisée à une ressource cible. De même, l'utilisation raisonnable d'une méthode sûre ne devrait causer aucun préjudice, aucune perte de propriété ni aucune charge inhabituelle au serveur d'origine.

L'implication est donc que les clients et les composants intermédiaires ont toute latitude pour invoquer une demande GET aussi souvent que nécessaire pour répondre à leurs propres préoccupations. Les araignées peuvent obtenir des ressources sans discernement pour mettre à jour leurs index. Les caches peuvent pré-chercher. Sur un réseau peu fiable, les messages perdus peuvent être retentés aussi souvent que nécessaire pour assurer au moins une réponse.

Il sera utilisé pour recharger les configurations, le cache, etc.

Si ces tâches sont coûteuses, vous ne voudrez peut-être pas que les clients émettent ces demandes à leur propre discrétion.

POSTd'autre part, est effectivement sans contrainte - cela réduit considérablement les hypothèses que les clients génériques sont autorisés à formuler. Vous n'obtenez pas de composants qui émettent des requêtes POST spéculatives car ils seraient fautifs - rien dans la norme ne dit que c'est OK.

PUT, PATCH, DELETE... ce sont des méthodes dangereuses avec une sémantique plus spécifiques que POST; leur pertinence dépendra de votre modèle de ressources.

Une idée importante à garder à l'esprit est que les méthodes HTTP appartiennent au domaine du document (voir l'exposé de Jim Webber en 2011 ), les effets que vous décrivez ne font probablement pas partie du domaine du document, mais sont plutôt des effets secondaires invoqués lorsque les documents sont modifiés. . Cela vous laisse une grande liberté quant à la manière dont vous organisez vos documents pour que le travail soit effectué.

VoiceOfUnreason
la source