Gardez à l'esprit que j'ai une compréhension rudimentaire de REST. Disons que j'ai cette URL:
http://api.animals.com/v1/dogs/1/
Et maintenant, je veux que le serveur fasse aboyer le chien. Seul le serveur sait comment faire cela. Disons que je veux le faire fonctionner sur un travail CRON qui fait aboyer le chien toutes les 10 minutes pour le reste de l'éternité. À quoi ressemble cet appel? Je veux faire ça:
Demande d'URL:
ACTION http://api.animals.com/v1/dogs/1/
Dans le corps de la requête:
{"action":"bark"}
Avant de vous fâcher contre moi pour avoir créé ma propre méthode HTTP, aidez-moi et donnez-moi une meilleure idée sur la façon dont je devrais invoquer une méthode côté serveur de manière REST. :)
MODIFIER POUR CLARIFICATION
Quelques précisions supplémentaires sur ce que fait la méthode "aboyer". Voici quelques options qui peuvent entraîner des appels d'API structurés différemment:
- aboyer envoie simplement un e-mail à dog.email et n'enregistre rien.
- bark envoie un e-mail à dog.email et incrémente dog.barkCount de 1.
- bark crée un nouvel enregistrement "aboiement" avec enregistrement bark.timestamp lorsque l'écorce s'est produite. Il incrémente également dog.barkCount de 1.
- bark exécute une commande système pour extraire la dernière version du code chien de Github. Il envoie ensuite un message texte à dog.owner leur indiquant que le nouveau code de chien est en cours de production.
la source
PATCH
peut être approprié. J'explique pourquoi vers la fin de ma réponse .Réponses:
Pourquoi viser un design RESTful?
Les principes RESTful apportent les fonctionnalités qui rendent les sites Web faciles (pour un utilisateur humain aléatoire de les «surfer») à la conception de l'API des services Web , de sorte qu'ils sont faciles à utiliser pour un programmeur. REST n'est pas bon parce que c'est REST, c'est bon parce que c'est bon. Et c'est bien surtout parce que c'est simple .
La simplicité de HTTP simple (sans enveloppes SOAP et
POST
services surchargés à URI unique ), ce que certains peuvent appeler «manque de fonctionnalités» , est en fait sa plus grande force . Dès le départ, HTTP vous demande d' adressabilité et d' apatridie : les deux décisions de conception de base qui permettent à HTTP de rester évolutif jusqu'aux méga-sites (et méga-services) d'aujourd'hui.Mais REST n'est pas la solution miracle: parfois un style RPC ("Remote Procedure Call" - comme SOAP) peut être approprié , et parfois d'autres besoins ont priorité sur les vertus du Web. C'est bon. Ce que nous n'aimons pas vraiment, c'est la complexité inutile . Trop souvent, un programmeur ou une entreprise fait appel à des services de style RPC pour un travail que l'ancien HTTP pourrait gérer très bien. L'effet est que HTTP est réduit à un protocole de transport pour une énorme charge XML qui explique ce qui se passe "vraiment" (pas l'URI ou la méthode HTTP en donnent un indice). Le service qui en résulte est beaucoup trop complexe, impossible à déboguer et ne fonctionnera pas à moins que vos clients n'aient la configuration exacte prévue par le développeur.
De la même manière qu'un code Java / C # ne peut pas être orienté objet, le simple fait d'utiliser HTTP ne rend pas une conception RESTful. On peut être pris dans la précipitation de penser à leurs services en termes d'actions et de méthodes à distance qu'il faudrait appeler. Pas étonnant que cela finisse principalement dans un service de style RPC (ou un hybride REST-RPC). La première étape consiste à penser différemment. Une conception RESTful peut être réalisée de plusieurs manières, l'une d'entre elles consiste à penser votre application en termes de ressources et non d'actions:
Je vais chercher des exemples ci-dessous. (Un autre aspect clé de REST est l'utilisation de HATEOAS - je ne le brosse pas ici, mais j'en parle rapidement dans un autre post .)
Problèmes de la première conception
Jetons un coup d'œil au design proposé:
Tout d'abord, nous ne devrions pas envisager de créer un nouveau verbe HTTP (
ACTION
). De manière générale, cela n'est pas souhaitable pour plusieurs raisons:ACTION
verbe existe?Considérons maintenant l' utilisation
POST
(je vais expliquer pourquoi ci-dessous, croyez-moi sur parole maintenant):Cela pourrait être OK ... mais seulement si :
{"action":"bark"}
était un document; et/v1/dogs/1/
était un URI de "processeur de document" (semblable à une usine). Un «processeur de document» est un URI sur lequel vous «jetez des choses» et «oubliez» - le processeur peut vous rediriger vers une ressource nouvellement créée après le «lancement». Par exemple, l'URI pour publier des messages dans un service de courtier de messages, qui, après la publication, vous redirigera vers un URI qui montre l'état du traitement du message.Je ne sais pas grand-chose de votre système, mais je parie déjà que les deux ne sont pas vrais:
{"action":"bark"}
n'est pas un document , c'est en fait la méthode que vous essayez de vous faufiler ninja dans le service; et/v1/dogs/1/
URI représente une ressource "chien" (probablement le chien avecid==1
) et non un processeur de document.Donc, tout ce que nous savons maintenant, c'est que la conception ci-dessus n'est pas si RESTful, mais qu'est-ce que c'est exactement? Qu'y a-t-il de si mauvais? Fondamentalement, c'est mauvais parce que c'est un URI complexe avec des significations complexes. Vous ne pouvez rien en déduire. Comment un programmeur pourrait-il savoir qu'un chien a une
bark
action qui peut être secrètement infusée avec unPOST
?Concevoir les appels API de votre question
Alors allons droit au but et essayons de concevoir ces aboiements de manière REST en pensant en termes de ressources . Permettez-moi de citer le livre Restful Web Services :
Suite à la description ci-dessus, nous pouvons voir que cela
bark
peut être modélisé comme unedog
sous -ressource de a (puisque abark
est contenu dans un chien, c'est-à-dire qu'un aboiement est "aboyé" par un chien).De ce raisonnement, nous avons déjà obtenu:
POST
/barks
, sous-ressource de chien:,/v1/dogs/1/barks
représentant unebark
"usine". Cet URI est unique pour chaque chien (car il est sous/v1/dogs/{id}
).Désormais, chaque cas de votre liste a un comportement spécifique.
1. Bark envoie juste un e-mail à
dog.email
et n'enregistre rien.Premièrement, aboyer (envoyer un e-mail) est-il une tâche synchrone ou asynchrone? Deuxièmement, la
bark
demande nécessite-t-elle un document (l'e-mail, peut-être) ou est-il vide?1.1 bark envoie un e-mail à
dog.email
et n'enregistre rien (en tant que tâche synchrone)Ce cas est simple. Un appel à la
barks
ressource d'usine donne immédiatement un aboiement (un e-mail envoyé) et la réponse (si OK ou non) est donnée immédiatement:Comme il n'enregistre (ne change) rien,
200 OK
c'est assez. Cela montre que tout s'est déroulé comme prévu.1.2 bark envoie un e-mail à
dog.email
et n'enregistre rien (en tant que tâche asynchrone)Dans ce cas, le client doit avoir un moyen de suivre la
bark
tâche. Labark
tâche doit alors être une ressource avec son propre URI:De cette façon, chacun
bark
est traçable. Le client peut alors émettre unGET
à l'bark
URI pour connaître son état actuel. Peut-être même utiliser unDELETE
pour l'annuler.2. bark envoie un e-mail à
dog.email
, puis incrémentedog.barkCount
de 1Celui-ci peut être plus délicat, si vous voulez informer le client que la
dog
ressource est modifiée:Dans ce cas, l'
location
intention de l'en- tête est de faire savoir au client qu'il doit jeter un coup d'œildog
. Depuis le RFC HTTP sur303
:Si la tâche est asynchrone, une sous-
bark
ressource est nécessaire tout comme la1.2
situation et303
doit être renvoyée en aGET .../barks/Y
lorsque la tâche est terminée.3. aboiement crée un nouveau "
bark
" enregistrement avecbark.timestamp
enregistrement lorsque l'écorce s'est produite. Il incrémente égalementdog.barkCount
de 1.Ici, le
bark
est créé en raison de la demande, le statut201 Created
est donc appliqué.Si la création est asynchrone, un
202 Accepted
est requis ( comme le dit la RFC HTTP ) à la place.L'horodatage enregistré fait partie de la
bark
ressource et peut être récupéré avec unGET
to. Le chien mis à jour peut également être "documenté"GET dogs/X/barks/Y
.4. bark exécute une commande système pour extraire la dernière version du code chien de Github. Il envoie ensuite un message texte pour
dog.owner
leur dire que le nouveau code chien est en cours de production.Le libellé de celui-ci est compliqué, mais c'est à peu près une tâche asynchrone simple:
Le client émettrait alors
GET
s pour/v1/dogs/1/barks/a65h44
connaître l'état actuel (si le code était extrait, l'e-mail était envoyé au propriétaire et autre). Chaque fois que le chien change, un303
est applicable.Emballer
Citant Roy Fielding :
Dans les exemples ci-dessus,
POST
est conçu de manière uniforme. Cela fera le chien "bark
". Ce n'est ni sûr (ce qui veut dire que bark a des effets sur les ressources), ni idempotent (chaque requête en produit un nouveaubark
), ce qui correspond bien auPOST
verbe.Un programmeur saurait: un
POST
àbarks
donne unbark
. Les codes d'état de la réponse (également avec le corps de l'entité et les en-têtes si nécessaire) expliquent ce qui a changé et comment le client peut et doit procéder.Remarque: Les principales sources utilisées étaient: le livre " Restful Web Services ", le HTTP RFC et le blog de Roy Fielding .
Éditer:
La question et donc la réponse ont beaucoup changé depuis leur création. La question initiale posée sur la conception d'un URI comme:
Vous trouverez ci-dessous l'explication des raisons pour lesquelles ce n'est pas un bon choix:
La manière dont les clients disent au serveur QUE FAIRE avec les données est l' information sur la méthode .
SUR QUELLE PARTIE des données [le client veut que le serveur] opère est l' information de portée .
À titre d'exemple, prenez l'URI de Google
http://www.google.com/search?q=DOG
. Là, les informations de méthode sontGET
et les informations de portée sont/search?q=DOG
.Longue histoire courte:
Et la règle d'or:
Vous pouvez mettre l ' "action" "aboyer" dans l'URL (ou dans le corps de l'entité) et l'utiliser
POST
. Pas de problème là-bas, cela fonctionne et peut être le moyen le plus simple de le faire, mais ce n'est pas RESTful .Pour garder votre service vraiment RESTful, vous devrez peut-être prendre du recul et réfléchir à ce que vous voulez vraiment faire ici (quels effets cela aura-t-il sur les ressources).
Je ne peux pas parler de vos besoins commerciaux spécifiques, mais laissez-moi vous donner un exemple: considérez un service de commande RESTful où les commandes sont à des URI comme
example.com/order/123
.Maintenant, disons que nous voulons annuler une commande, comment allons-nous le faire? On peut être tenté de penser qu'il s'agit d'une «action» d' annulation et de la concevoir comme .
POST example.com/order/123?do=cancel
Ce n'est pas RESTful, comme nous l'avons mentionné ci-dessus. Au lieu de cela, nous pourrions
PUT
une nouvelle représentation duorder
avec uncanceled
élément envoyé àtrue
:Et c'est tout. Si la commande ne peut pas être annulée, un code de statut spécifique peut être retourné. (Une conception de sous-ressource, comme
POST /order/123/canceled
avec le corps de l'entitétrue
peut, pour plus de simplicité, être également disponible.)Dans votre scénario spécifique, vous pouvez essayer quelque chose de similaire. De cette façon, pendant qu'un chien aboie, par exemple, un
GET
at/v1/dogs/1/
pourrait inclure cette information (par exemple<barking>true</barking>
) . Ou ... si c'est trop compliqué, assouplissez votre exigence RESTful et tenez-vous-enPOST
.Mettre à jour:
Je ne veux pas que la réponse soit trop grande, mais cela prend un certain temps pour maîtriser l'exposition d'un algorithme (une action ) en tant qu'ensemble de ressources. Au lieu de penser en termes d'actions ( "faire une recherche de lieux sur la carte" ), il faut penser en termes de résultats de cette action ( "la liste des lieux sur la carte correspondant à un critère de recherche" ).
Vous pouvez vous retrouver à revenir à cette étape si vous constatez que votre conception ne correspond pas à l'interface uniforme de HTTP.
Les variables de requête sont des informations de portée , mais ne dénotent pas de nouvelles ressources (il
/post?lang=en
s'agit clairement de la même ressource que/post?lang=jp
, juste une représentation différente). Au contraire, ils sont utilisés pour transmettre l'état du client (comme?page=10
, pour que l'état ne soit pas conservé dans le serveur;?lang=en
est également un exemple ici) ou des paramètres d'entrée aux ressources algorithmiques (/search?q=dogs
,/dogs?code=1
). Encore une fois, pas de ressources distinctes.Propriétés des verbes HTTP (méthodes):
Un autre point clair qui apparaît
?action=something
dans l'URI n'est pas RESTful, ce sont les propriétés des verbes HTTP:GET
etHEAD
sont sûrs (et idempotents);PUT
etDELETE
sont idempotents seulement;POST
est ni.Sécurité : Une demande
GET
ouHEAD
est une demande de lecture de certaines données, pas une demande de modification d'un état de serveur. Le client peut faire une demandeGET
ouHEAD
10 fois et c'est la même chose qu'une seule fois, ou ne jamais le faire du tout .Idempotence : Une opération idempotente en un qui a le même effet que vous l'appliquiez une ou plusieurs fois (en maths, multiplier par zéro est idempotent). Si vous avez
DELETE
une ressource une fois, la suppression à nouveau aura le même effet (la ressource estGONE
déjà).POST
n'est ni sûr ni idempotent. Faire deuxPOST
demandes identiques à une ressource «usine» entraînera probablement deux ressources subordonnées contenant les mêmes informations. Avec surchargé (méthode en URI ou entité-corps)POST
, tous les paris sont ouverts.Ces deux propriétés étaient importantes pour le succès du protocole HTTP (sur des réseaux peu fiables!): Combien de fois avez-vous mis à jour (
GET
) la page sans attendre qu'elle soit complètement chargée?Créer une action et la placer dans l'URL rompt clairement le contrat des méthodes HTTP. Encore une fois, la technologie vous permet, vous pouvez le faire, mais ce n'est pas une conception RESTful.
la source
POST
a été conçu pour "fournir un bloc de données ... à un processus de traitement de données" . Il semble que beaucoup de gens distinguent les ressources des actions, mais en réalité les actions ne sont qu'un type de ressource.POST
"fournir un bloc de données ... à un processus de traitement des données", mais la différence est vraiment que, un bloc de données , pas un bloc de données et la procédure (action, méthode, commande) à être exécuté le alors. C'est unePOST
surcharge, et laPOST
surcharge est une conception de style RPC, pas RESTful.J'ai répondu plus tôt , mais cette réponse contredit ma vieille réponse et suit une stratégie très différente pour arriver à une solution. Il montre comment la requête HTTP est construite à partir des concepts qui définissent REST et HTTP. Il utilise également à la
PATCH
place dePOST
ouPUT
.Il passe par les contraintes REST, puis les composants de HTTP, puis une solution possible.
DU REPOS
REST est un ensemble de contraintes destiné à être appliqué à un système hypermédia distribué afin de le rendre évolutif. Même pour en comprendre le sens dans le contexte du contrôle à distance d'une action, vous devez penser au contrôle à distance d'une action comme faisant partie d'un système hypermédia distribué - une partie d'un système de découverte, de visualisation et de modification d'informations interconnectées. Si cela pose plus de problèmes que cela ne vaut la peine, alors il n'est probablement pas bon d'essayer de le rendre RESTful. Si vous voulez juste une interface graphique de type "panneau de contrôle" sur le client qui peut déclencher des actions sur le serveur via le port 80, alors vous voulez probablement une interface RPC simple comme JSON-RPC via des requêtes / réponses HTTP ou un WebSocket.
Mais REST est une façon de penser fascinante et l'exemple de la question se trouve être facile à modéliser avec une interface RESTful, alors relevons le défi pour le plaisir et pour l'éducation.
REST est défini par quatre contraintes d'interface:
Vous vous demandez comment vous pouvez définir une interface, répondant à ces contraintes, via laquelle un ordinateur demande à un autre ordinateur de faire aboyer un chien. Plus précisément, vous voulez que votre interface soit HTTP et vous ne voulez pas ignorer les fonctionnalités qui rendent HTTP RESTful lorsqu'il est utilisé comme prévu.
Commençons par la première contrainte: l'identification des ressources .
Un chien est donc une ressource. Il doit être identifié.
Vous modélisez un chien en prenant un ensemble d'identifiants et de représentations et en disant qu'ils sont tous associés les uns aux autres à un moment donné. Pour l'instant, utilisons l'identifiant "dog # 1". Cela nous amène aux deuxième et troisième contraintes: la représentation des ressources et l' auto-description .
Voici une séquence d'octets capturant l'état prévu du chien, c'est-à-dire la représentation que l'on souhaite associer à l'identifiant "dog # 1" (notez qu'il ne représente qu'une partie de l'état car il ne considère pas le nom du chien, sa santé , ou même des aboiements passés):
Il est censé être attaché aux métadonnées qui le décrivent. Ces métadonnées peuvent être utiles:
Enfin, regardons la quatrième contrainte: HATEOAS .
Dans une interface RESTful, le client reçoit une représentation de ressource afin de déterminer comment il doit recevoir ou envoyer une représentation. Il doit y avoir une représentation quelque part dans l'application à partir de laquelle le client peut comprendre comment recevoir ou envoyer toutes les représentations qu'il devrait pouvoir recevoir ou envoyer, même s'il suit une chaîne de représentations pour arriver à cette information. Cela semble assez simple:
Le client demande une représentation d'une ressource identifiée comme la page d'accueil; en réponse, il obtient une représentation contenant un identifiant de chaque chien souhaité par le client. Le client en extrait un identifiant et demande au service comment il peut interagir avec le chien identifié, et le service dit que le client peut envoyer une déclaration en anglais décrivant une partie de l'état prévu du chien. Ensuite, le client envoie une telle déclaration et reçoit un message de réussite ou un message d'erreur.
HTTP
HTTP implémente les contraintes REST comme suit:
l' identification des ressources : URI
représentation de ressource : corps d'entité
auto-description : méthode ou code d'état, en-têtes et éventuellement des parties du corps de l'entité (par exemple l'URI d'un schéma XML)
HATEOAS : hyperliens
Vous avez choisi
http://api.animals.com/v1/dogs/1
comme URI. Supposons que le client ait obtenu cela sur une page du site.Utilisons ce corps d'entité (la valeur de
next
est un horodatage; une valeur de0
signifie `` lorsque cette demande est reçue ''):Maintenant, nous avons besoin d'une méthode. PATCH correspond à la description "partie de l'état prévu" que nous avons choisi:
Et quelques en-têtes:
Pour indiquer la langue du corps de l'entité:
Content-Type: application/json
Pour vous assurer que cela n'arrive qu'une seule fois:
If-Unmodified-Since: <date/time this was first sent>
Et nous avons une demande:
En cas de succès, le client doit recevoir un
204
code d'état en réponse, ou un205
si la représentation de/v1/dogs/1/
a changé pour refléter le nouveau calendrier d'aboiements.En cas d'échec, il devrait recevoir un
403
message expliquant pourquoi.Il n'est pas essentiel de REST pour que le service reflète la planification des aboiements dans une représentation en réponse à
GET /v1/dogs/1/
, mais cela aurait plus de sens si une représentation JSON incluait ceci:Traitez le travail cron comme un détail d'implémentation que le serveur cache à l'interface. C'est la beauté d'une interface générique. Le client n'a pas besoin de savoir ce que fait le serveur dans les coulisses; tout ce qui compte, c'est que le service comprenne et réponde aux changements d'état demandés.
la source
La plupart des gens utilisent POST à cette fin. Il est approprié pour effectuer "toute opération non sécurisée ou non idempotente lorsqu'aucune autre méthode HTTP ne semble appropriée".
Les API telles que XMLRPC utilisent POST pour déclencher des actions qui peuvent exécuter du code arbitraire. L '"action" est incluse dans les données POST:
Le RPC est un exemple pour montrer que POST est le choix conventionnel des verbes HTTP pour les méthodes côté serveur. Voici les réflexions de Roy Fielding sur POST - il dit à peu près qu'il est RESTful d'utiliser les méthodes HTTP comme spécifié.
Notez que RPC lui-même n'est pas très REST car il n'est pas orienté ressources. Mais si vous avez besoin d'apatridie, de mise en cache ou de couches, il n'est pas difficile d'effectuer les transformations appropriées. Voir http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ pour un exemple.
la source
POST api.animals.com/v1/dogs1?action=bark
/RPC2
ne fait rien pour identifier une ressource - il identifie une technologie de serveur. Au lieu de cela, celamethodName
essaie d '«identifier» la «ressource» - mais même dans ce cas, il ne bénéficie pas de la distinction nom / verbe; la seule chose semblable à un «verbe» ici estmethodCall
. C'est comme «faire la récupération du nom de l'état» au lieu de «récupérer le nom de l'état» - ce dernier a tellement plus de sens.POST
est la méthode HTTP conçue pourLes méthodes côté serveur gérant les actions non mappées CRUD sont ce que Roy Fielding a prévu avec REST, donc vous êtes bon là-bas, et c'est pourquoi il a
POST
été conçu pour être non idempotent.POST
traitera la plupart des publications de données vers des méthodes côté serveur pour traiter les informations.Cela dit, dans votre scénario d'aboiement de chien, si vous voulez qu'un aboiement côté serveur soit effectué toutes les 10 minutes, mais que pour une raison quelconque, vous avez besoin que le déclencheur provienne d'un client,
PUT
cela servirait mieux le but, en raison de son idempotence. Eh bien, strictement selon ce scénario, il n'y a pas de risque apparent que plusieurs requêtes POST provoquent un miaulement de votre chien, mais c'est de toute façon le but des deux méthodes similaires. Ma réponse à une question SO similaire peut vous être utile.la source
PUT
URL se réfère à ce qui doit être remplacé par le contenu du client et l'POST
URL se réfère à ce qui devrait traiter le contenu du client comme il le souhaite.Si nous supposons que Barking est une ressource interne / dépendante / secondaire sur laquelle le consommateur peut agir, alors nous pourrions dire:
le chien numéro 1 aboie
renvoie le dernier horodatage de l'écorce
ne s'applique pas! alors ignorez-le.
la source
/v1/dogs/1/bark
être une ressource en soi etPOST
une description de la manière dont l'état interne de cette ressource doit changer. Je trouve qu'il est plus logique de simplement considérer/v1/dogs/1/
comme une ressource et d'indiquer dans l'entité-corps qu'il doit aboyer.Les révisions précédentes de certaines réponses suggéraient d'utiliser RPC. Vous n'avez pas besoin de vous tourner vers RPC car il est parfaitement possible de faire ce que vous voulez tout en respectant les contraintes REST.
Tout d'abord, ne mettez pas de paramètres d'action dans l'URL. L'URL définit à quoi vous appliquez l'action et les paramètres de requête font partie de l'URL. Il devrait être pensé entièrement comme un nom.
http://api.animals.com/v1/dogs/1/?action=bark
est une ressource différente - un nom différent - àhttp://api.animals.com/v1/dogs/1/
. [nb Asker a supprimé l'?action=bark
URI de la question.] Par exemple, comparezhttp://api.animals.com/v1/dogs/?id=1
àhttp://api.animals.com/v1/dogs/?id=2
. Différentes ressources, distinguées uniquement par la chaîne de requête. Ainsi l'action de votre requête, à moins qu'elle ne corresponde directement à un type de méthode existant sans corps (TRACE, OPTIONS, HEAD, GET, DELETE, etc.) doit être définie dans le corps de la requête.Ensuite, décidez si l'action est " idempotente ", ce qui signifie qu'elle peut être répétée sans effet indésirable (voir le paragraphe suivant pour plus d'explications). Par exemple, la définition d'une valeur sur true peut être répétée si le client n'est pas sûr que l'effet souhaité s'est produit. Ils envoient à nouveau la demande et la valeur reste vraie. Ajouter 1 à un nombre n'est pas idempotent. Si le client envoie la commande Add1, n'est pas sûr que cela a fonctionné et la renvoie à nouveau, le serveur en a-t-il ajouté un ou deux? Une fois que vous avez déterminé cela, vous êtes mieux placé pour choisir entre
PUT
etPOST
pour votre méthode.Idempotent signifie qu'une demande peut être répétée sans changer le résultat. Ces effets n'incluent pas la journalisation et d'autres activités d'administration de serveur de ce type. En utilisant vos premier et deuxième exemples, envoyer deux e-mails à la même personne entraîne un état différent de l'envoi d'un e-mail (le destinataire en a deux dans sa boîte de réception, qu'il pourrait considérer comme du spam), donc j'utiliserais certainement POST pour cela. . Si le barkCount dans l'exemple 2 est destiné à être vu par un utilisateur de votre API ou affecte quelque chose qui est visible par le client, alors c'est aussi quelque chose qui rendrait la demande non idempotente. S'il ne doit être visualisé que par vous, il compte comme une journalisation du serveur et doit être ignoré lors de la détermination de l'idempotence.
Enfin, déterminez si l'action que vous souhaitez effectuer devrait réussir immédiatement ou non. BarkDog est une action qui se termine rapidement. RunMarathon ne l'est pas. Si votre action est lente, envisagez de renvoyer un
202 Accepted
, avec une URL dans le corps de la réponse pour qu'un utilisateur interroge pour voir si l'action est terminée. Vous pouvez également demander aux utilisateurs de POSTER sur une URL de liste comme/marathons-in-progress/
, puis lorsque l'action est terminée, redirigez-les de l'URL d'ID en cours vers l'/marathons-complete/
URL.Pour les cas spécifiques n ° 1 et n ° 2, je demanderais au serveur d'héberger une file d'attente et que le client y poste des lots d'adresses. L'action ne serait pas SendEmails, mais quelque chose comme AddToDispatchQueue. Le serveur peut ensuite interroger la file d'attente pour voir s'il y a des adresses e-mail en attente et envoyer des e-mails s'il en trouve. Il met ensuite à jour la file d'attente pour indiquer que l'action en attente a maintenant été effectuée. Vous auriez un autre URI indiquant au client l'état actuel de la file d'attente. Pour éviter le double envoi d'e-mails, le serveur peut également conserver un journal de la personne à qui il a envoyé cet e-mail et vérifier chaque adresse par rapport à celle-ci pour s'assurer qu'il n'en envoie jamais deux à la même adresse, même si vous POSTUREZ la même liste deux fois à La queue.
Lorsque vous choisissez un URI pour quoi que ce soit, essayez de penser à cela comme un résultat, pas comme une action. Par exemple,
google.com/search?q=dogs
affiche les résultats d'une recherche sur le mot «chiens». Il n'effectue pas nécessairement la recherche.Les cas n ° 3 et n ° 4 de votre liste ne sont pas non plus des actions idempotentes. Vous suggérez que les différents effets suggérés pourraient affecter la conception de l'API. Dans les quatre cas, j'utiliserais la même API, car les quatre modifient «l'état du monde».
la source
Voir ma nouvelle réponse - elle contredit celle-ci et explique REST et HTTP plus clairement et plus précisément.
Voici une recommandation qui se trouve être RESTful mais qui n'est certainement pas la seule option. Pour commencer à aboyer lorsque le service reçoit la demande:
token
est un nombre arbitraire qui empêche les aboiements redondants quel que soit le nombre de fois que cette demande est envoyée.next
indique l'heure de l'écorce suivante; une valeur de0
signifie «ASAP».Chaque fois que vous
GET /v1/dogs/1/bark-schedule
, vous devriez obtenir quelque chose comme ça, où t est l'heure du dernier aboiement et u est t + 10 minutes:{"last": t, "next": u}
Je vous recommande vivement d'utiliser la même URL pour demander un aboiement que vous utilisez pour connaître l'état d'aboiement actuel du chien. Ce n'est pas essentiel pour REST, mais cela met l'accent sur l'acte de modifier le calendrier.
Le code d'état approprié est probablement 205 . J'imagine un client qui regarde le planning actuel,
POST
s à la même URL pour le changer, et est chargé par le service de donner un second regard au planning pour prouver qu'il a été changé.Explication
DU REPOS
Oubliez HTTP pendant un moment. Il est essentiel de comprendre qu'une ressource est une fonction qui prend du temps en entrée et renvoie un ensemble contenant des identificateurs et des représentations . Simplifions cela: une ressource est un ensemble R d'identificateurs et de représentations; R peut changer - les membres peuvent être ajoutés, supprimés ou modifiés. (Bien qu'il soit mauvais, la conception instable pour supprimer ou modifier des identifiants.) Nous disons un identifiant qui est un élément de R identifie R , et une représentation qui est un élément de R représente R .
Disons que R est un chien. Vous identifiez R comme
/v1/dogs/1
. (Signification/v1/dogs/1
est membre de R .) C'est juste l' une des nombreuses façons dont vous pouvez identifier R . Vous pouvez également identifier R au fur/v1/dogs/1/x-rays
et à mesure/v1/rufus
.Comment représentez-vous R ? Peut-être avec une photo. Peut-être avec une série de rayons X. Ou peut-être avec une indication de la date et de l'heure de la dernière aboiement de R. Mais rappelez-vous que ce sont toutes des représentations de la même ressource .
/v1/dogs/1/x-rays
est un identifiant de la même ressource qui est représenté par une réponse à la question "quand R a- t-il aboyé pour la dernière fois?"HTTP
Les représentations multiples d'une ressource ne sont pas très utiles si vous ne pouvez pas faire référence à celle que vous souhaitez. C'est pourquoi HTTP est utile: il vous permet de connecter des identifiants aux représentations . Autrement dit, il s'agit d'un moyen pour le service de recevoir une URL et de décider quelle représentation servir au client.
Du moins, c'est ce que
GET
fait.PUT
est fondamentalement l'inverse deGET
: vousPUT
une représentation r à l'URL si vous souhaitez que les futuresGET
requêtes à cette URL retournent r , avec quelques traductions possibles comme JSON en HTML.POST
est une manière plus souple de modifier une représentation. Pensez à la logique d'affichage et à la logique de modification qui sont équivalentes l'une à l'autre - toutes deux correspondant à la même URL. Une demande POST est une demande pour que la logique de modification traite les informations et modifie toutes les représentations (pas seulement la représentation localisée par la même URL) comme le service le juge opportun. Faites attention au troisième paragraphe après 9.6 PUT : vous ne remplacez pas la chose à l'URL par un nouveau contenu; vous demandez à la chose à l'URL de traiter certaines informations et de répondre intelligemment sous la forme de représentations informatives.Dans notre cas, nous demandons à la logique de modification at
/v1/dogs/1/bark-schedule
(qui est la contrepartie de la logique d'affichage qui nous indique quand il a aboyé pour la dernière fois et quand il aboyera ensuite) de traiter nos informations et de modifier certaines représentations en conséquence. En réponse aux futursGET
s, la logique d'affichage correspondant à la même URL nous dira que le chien aboie maintenant comme nous le souhaitons.Considérez le travail cron comme un détail d'implémentation. HTTP traite de l'affichage et de la modification des représentations. À partir de maintenant, le service indiquera au client quand le chien a aboyé pour la dernière fois et quand il aboyera ensuite. Du point de vue du service, c'est honnête car ces heures correspondent aux tâches cron passées et prévues.
la source
REST est un standard orienté ressources, il n'est pas piloté par l'action comme le serait un RPC.
Si vous voulez que votre serveur aboie , vous devriez vous pencher sur différentes idées telles que JSON-RPC ou dans la communication Websockets.
À mon avis, chaque tentative de le garder RESTful échouera: vous pouvez émettre un
POST
avec leaction
paramètre, vous ne créez pas de nouvelles ressources mais comme vous pouvez avoir des effets secondaires, vous êtes plus en sécurité.la source
POST
a été conçu pour "fournir un bloc de données ... à un processus de traitement de données" . Il semble que beaucoup de gens distinguent les ressources des actions, mais en réalité les actions ne sont qu'un type de ressource. L'appel d'une ressource d'action sur un serveur reste une interface uniforme, pouvant être mise en cache, modulaire et évolutive. Il est également sans état, mais cela peut être violé si le client est conçu pour attendre une réponse. Mais appeler une "méthode void" sur le serveur est ce que Roy Fielding a prévu avec REST .