Je prévois de construire une API RESTfull, mais certaines questions d’architecture me posent certains problèmes. L'ajout d'une logique de gestion de portefeuille aux clients est une option que j'aimerais éviter, car la mise à jour de plusieurs plates-formes clientes est difficile à gérer en temps réel, lorsque la logique de gestion peut rapidement changer.
Disons que nous avons l'article en tant que ressource (api / article), comment devrions-nous mettre en œuvre des actions telles que publier, annuler la publication, activer ou désactiver, etc., tout en essayant de le garder aussi simple que possible?
1) Devons-nous utiliser api / article / {id} / {action}, car beaucoup de logique de base peut y être appliquée, comme pousser vers des emplacements distants ou modifier plusieurs propriétés. La chose la plus difficile ici est probablement que nous devons renvoyer toutes les données d'article à l'API pour la mise à jour et que le travail multi-utilisateur ne peut pas être mis en œuvre. Par exemple, l'éditeur pourrait envoyer des données plus anciennes de 5 secondes et corriger un écrasement qu'un autre journaliste vient de faire il y a 2 secondes. Je ne peux absolument pas expliquer cela aux clients, car ceux qui publient un article ne sont aucunement liés à la mise à jour du contenu.
2) Créer une nouvelle ressource peut également être une option, api / article- {action} / id, mais la ressource renvoyée ne serait alors pas article- {action} mais un article dont je ne suis pas sûr si cela est approprié. De plus, dans la classe d’article code côté serveur, le traitement est effectué sur les deux ressources et je ne sais pas si cela va à l’encontre de la pensée RESTfull.
Toutes les suggestions sont les bienvenues ..
api/article?action=publish
? Les paramètres de requête sont destinés aux cas où l'état de la ressource dépend de l'algorithme (ou de l'action) que vous mentionnez. Par exemple,api/articles?sort=asc
est valideRéponses:
Je trouve les pratiques décrites ici utiles:
la source
/article/123/deactivations
pour créer une nouvelle demande de désactivation pour l'article 123, le serveur risque non seulement de désactiver la ressource demandée, mais également de stocker ma demande de désactivation afin de pouvoir récupérer son statut ultérieurement.PUT /gists/:id/star
pasPOST /gists/:id/star
?Les opérations qui entraînent des modifications majeures de l'état et du comportement côté serveur, telles que l'action "publier" que vous décrivez, sont difficiles à modéliser explicitement dans REST. Une solution que je vois souvent est de conduire implicitement un tel comportement complexe à travers les données.
Pensez à commander des produits via une API REST exposée par un commerçant en ligne. La commande est une opération complexe. Plusieurs produits seront emballés et expédiés, votre compte sera débité et vous recevrez un reçu. Vous pouvez annuler votre commande pour une durée limitée et il existe bien sûr une garantie de remboursement intégral vous permettant de renvoyer des produits pour un remboursement.
Au lieu d'une opération d'achat complexe, une telle API peut vous permettre de créer une nouvelle ressource, une commande d'achat. Au début, vous pouvez y apporter les modifications souhaitées: ajouter ou supprimer des produits, modifier l'adresse de livraison, choisir une autre option de paiement ou annuler votre commande. Vous pouvez faire tout cela parce que vous n’avez encore rien acheté, vous manipulez simplement des données sur le serveur.
Une fois votre commande terminée et le délai de grâce écoulé, le serveur verrouille votre commande pour empêcher toute modification ultérieure. Ce n’est qu’à ce moment-là que la séquence complexe d’opérations commence, mais vous ne pouvez pas la contrôler directement, mais indirectement par le biais des données que vous avez précédemment placées dans la commande.
Selon votre description, "publier" pourrait être mis en œuvre de cette manière. Au lieu d'exposer une opération, vous placez une copie du brouillon que vous avez examiné et que vous souhaitez publier en tant que nouvelle ressource sous / publier. Cela garantit que les éventuelles mises à jour ultérieures du brouillon ne seront pas publiées, même si l'opération de publication elle-même se termine des heures plus tard.
la source
Peu importe ce que vous faites, ce type de problème est un défi. Il s'agit d'un problème très similaire au contrôle de source distribué (mercurial, git, etc.), et la solution, épelée dans HTTP / ReST, semble un peu similaire.
Supposons que deux utilisateurs, Alice et Bob, travaillent tous les deux
/articles/lunch
. (pour plus de clarté, la réponse est en gras)Tout d’abord, alice crée l’article.
Le serveur n'a pas créé de ressource, car il n'y avait pas de "version" attachée à la demande (en supposant un identifiant de
/articles/{id}/{version}
. Pour effectuer la création, Alice a été redirigée vers l'URL de l'article / de la version qu'elle va créer. L'utilisateur d'Alice L'agent réappliquera alors la demande à la nouvelle adresse.Et maintenant, l'article a été créé. Ensuite, Bob regarde l'article:
Bob regarde là:
Il décide d'ajouter sa propre monnaie.
Comme avec Alice, Bob est redirigé vers où il créera une nouvelle version.
Finalement, Alice décide d’ajouter à son propre article:
Au lieu d'être redirigé normalement, un code d'état différent est renvoyé au client
409
, ce qui indique à Alice que la version à partir de laquelle elle essayait de créer une branche a déjà été créée. De toute façon, les nouvelles ressources ont été créées (comme le montre l'en-Location
tête) et les différences entre les deux ont été incluses dans le corps de la réponse. Alice sait maintenant que la demande qu'elle vient de faire doit être fusionnée en quelque sorte.Toute cette redirection est liée à la sémantique de
PUT
, ce qui nécessite la création de nouvelles ressources exactement à l'endroit demandé par la ligne de requête. cela pourrait aussi économiser un cycle de requête en utilisant laPOST
place, mais le numéro de version devrait alors être encodé dans la requête par une autre magie, ce qui me paraissait moins évident aux fins d'illustration, mais serait probablement préféré dans une vraie API. minimiser les cycles de demande / réponse.la source
Voici un autre exemple qui traite non pas du contenu des documents mais davantage de l’état transitoire. (Je trouve des versions - étant donné qu'en général, chaque version peut constituer une nouvelle ressource - une sorte de problème facile.)
Supposons que je souhaite exposer un service exécuté sur une machine via un REST afin qu'il puisse être arrêté, démarré, redémarré, etc.
Quelle est l'approche la plus reposante ici? POST / service? Commande = redémarrer, par exemple? Ou POST / service / état avec un corps de, disons, «en cours d'exécution»?
Il serait bien de codifier ici les meilleures pratiques et de savoir si REST est la bonne approche dans ce type de situation.
Deuxièmement, supposons que je souhaite diriger une action d’un service qui n’affecte pas son propre état, mais déclenche plutôt un effet secondaire. Par exemple, un service de messagerie qui envoie un rapport, créé au moment de l'appel, à plusieurs adresses e-mail.
GET / report peut être un moyen d’obtenir moi-même une copie du rapport; mais que se passe-t-il si nous voulons pousser du côté serveur d'autres actions telles que l'envoi par courrier électronique, comme je le dis ci-dessus Ou écrire dans une base de données.
Ces cas vont dans le sens de la fracture ressources-actions, et je vois des moyens de les gérer de manière orientée REST, mais franchement, c'est un peu comme un bidouillage. La question clé est peut-être de savoir si une API REST devrait prendre en charge les effets secondaires en général.
la source
REST est orienté données et, de ce fait, les ressources fonctionnent mieux comme des "choses" que des actions. La sémantique implicite des méthodes http; GET, PUT, DELETE, etc. servent à renforcer l’orientation. POST bien sûr, est l'exception.
Une ressource peut être un mélange de données c'est-à-dire. contenu de l'article; et métadonnées c'est-à-dire. publié, verrouillé, révision. Il existe de nombreuses autres manières possibles de découper les données, mais vous devez tout d’abord définir l’apparence du flux de données afin de déterminer celui qui est le plus optimal (s’il en existe un). Par exemple, il se peut que les révisions soient leur propre ressource dans l'article, comme le suggère TokenMacGuy.
En ce qui concerne la mise en œuvre, je ferais probablement quelque chose comme ce que suggère TockenMacGuy. J'ajouterais également des champs de métadonnées sur article, pas de révision, comme "verrouillés" et "publiés".
la source
Ne pensez pas que cela manipule directement l'état de l'article. Au lieu de cela, vous créez un ordre de modification pour demander la création de l'article.
Vous pouvez modéliser la mise en ordre de modification en créant une nouvelle ressource d'ordre de modification (POST). Il y a beaucoup d'avantages. Par exemple, vous pouvez spécifier une date et une heure futures pour la publication de l'article dans l'ordre de modification, et laisser le serveur se soucier de la mise en œuvre.
Si la publication n'est pas un processus instantané, il n'est pas nécessaire d'attendre la fin de l'opération pour revenir au client. Vous venez de reconnaître que la demande de changement a été créée et de renvoyer l'ID de demande de changement. Vous pouvez ensuite utiliser l'URL correspondant à cette demande de changement pour partager le statut de celle-ci.
L'un des éléments clés pour moi a été de reconnaître que cette métaphore d'ordre de changement n'est qu'un autre moyen de décrire la programmation orientée objet. Au lieu de ressources, nous appelons alors des objets. Au lieu de commandes de changement, nous les appelons des messages. Une façon d'envoyer un message de A à B dans OO consiste à faire en sorte que A appelle une méthode sur B. Une autre façon de le faire, en particulier lorsque A et B se trouvent sur des ordinateurs différents, consiste à faire en sorte que A crée un nouvel objet, M, et envoyez-le à B. REST formalise simplement ce processus.
la source
Si je vous ai bien compris, je pense que ce que vous avez est davantage un problème de détermination de "règle de gestion" qu'un problème technique.
Le fait qu’un article puisse être écrasé peut être résolu en introduisant des niveaux d’autorisation permettant aux utilisateurs expérimentés de remplacer les versions des utilisateurs juniors.En introduisant également des versions, ainsi qu’une colonne permettant de saisir l’état de l’article (par exemple, 'en développement', 'final' , etc.), vous pourriez surmonter cela. Vous pouvez également donner à l'utilisateur la possibilité de sélectionner une version donnée en combinant le moment de la soumission et le numéro de version.
Dans tous les cas ci-dessus, votre service doit implémenter les règles métier que vous avez définies. Vous pouvez donc appeler le service avec les paramètres suivants: userid, article, version, action (où la version est facultative, cela dépend également de vos règles commerciales).
la source