Nous avons une URL au format suivant
/ instance/{instanceType}/{instanceId}
Vous pouvez l'appeler avec les méthodes HTTP standard: POST, GET, DELETE, PUT. Cependant, il y a quelques autres actions que nous prenons à ce sujet, comme "Enregistrer en tant que brouillon" ou "Curate"
Nous pensions que nous pourrions simplement utiliser des méthodes HTTP personnalisées comme: DRAFT, VALIDATE, CURATE
Je pense que c'est acceptable car les normes disent
"L'ensemble des méthodes courantes pour HTTP/1.1 est défini ci-dessous. Bien que cet ensemble puisse être étendu, des méthodes supplémentaires ne peuvent pas être supposées partager la même sémantique pour les clients et serveurs étendus séparément."
Et des outils comme WebDav créent certaines de leurs propres extensions.
Y a-t-il des problèmes rencontrés par quelqu'un avec des méthodes personnalisées? Je pense aux serveurs proxy et aux pare-feu, mais tout autre sujet de préoccupation est le bienvenu. Dois-je rester du bon côté et avoir juste un paramètre d'URL comme action = valider | curate | draft?
L'une des contraintes fondamentales de HTTP et la caractéristique de conception centrale de REST est un interface uniforme fournie (entre autres) par un petit ensemble fixe de méthodes qui s'appliquent universellement à toutes les ressources. La contrainte d'interface uniforme a un certain nombre d'avantages et d'inconvénients. Je cite de Fielding généreusement ici.
Une interface uniforme:
En revanche, une interface uniforme:
Les compromis sont "conçus pour le cas commun du Web" et ont permis de construire un vaste écosystème qui fournit des solutions à de nombreux problèmes courants dans les architectures Web. L'adhésion à une interface uniforme permettra à votre système de bénéficier de cet écosystème tout en le brisant, il sera si difficile. Vous souhaiterez peut-être utiliser un équilibreur de charge comme nginx, mais vous ne pouvez désormais utiliser qu'un équilibreur de charge qui comprend DRAFT et CURATE. Vous souhaiterez peut-être utiliser une couche de cache HTTP comme Varnish, mais vous ne pouvez désormais utiliser qu'une couche de cache HTTP qui comprend DRAFT et CURATE. Vous voudrez peut-être demander à quelqu'un de vous aider à résoudre une panne de serveur, mais personne d'autre ne connaît la sémantique d'une demande CURATE. Il peut être difficile de modifier vos bibliothèques client ou serveur préférées pour comprendre et implémenter correctement les nouvelles méthodes. Etc.
La bonne* La manière de représenter ceci est une transformation d'état sur la ressource (ou les ressources associées). Vous ne rédigez PAS une publication, vous transformez son état draft
en true
ou vous créez une ressource draft
qui contient les modifications et les liens vers les versions précédentes. Vous NE CUREZ PAS une publication, vous transformez son état curated
en true
ou créez une ressource curation
qui relie la publication à l'utilisateur qui l'a organisée.
* Correct en ce sens qu'il suit le plus fidèlement les principes architecturaux REST.
Je préférerais les concevoir comme des sous-ressources, sur lesquelles vous effectuez une demande POST.
Considérez que vous avez une ressource à /instance/type/1
, Je souhaiterais que la représentation de cette ressource transmette quelques liens vers des "actions" pouvant être effectuées sur la ressource, telles que /instance/type/1/draft
et /instance/type/1/curate
. En JSON, cela pourrait être aussi simple que:
{
"some property":"the usual value",
"state": "we can still inform the client about the current state",
"draft": "http://server/instance/type/1/draft",
"curate": "http://server/instance/type/1/curate"
}
Cela permet au client d'être très explicite sur ce qui doit se produire, lors de la demande POST vers le lien fourni par le membre curate
. La ressource publiée peut inclure des arguments qui détaillent l'événement qui entraînerait peut-être une transition étatique.
Aller avec l'approche "naïve" de se déplacer entre les états possibles sur une ressource a l'inconvénient de ne pas saisir quels événements ont conduit à ces transitions.
Les transitions d'état se produisent généralement en réponse à des événements spécifiques, et je préfère capturer ces événements plutôt que de laisser le client décider que quelque chose est maintenant dans un "état" spécifique. Cela rend également la validation beaucoup plus difficile. De plus, vous ne seriez pas en mesure de saisir des "arguments" à moins de les décrire également dans l'État lui-même. Et puis ça devient compliqué quand du code change ceux sans transition d'état réel, et la validation requise, et le tout devient rapidement un gâchis.
Je pense que la méthode HTTP personnalisée est le meilleur moyen d'implémenter des actions d'entité. L'ajout de l'action au corps de l'entité (POST) ne semble pas correct, cela ne fait pas partie de votre entité (bien que le résultat puisse y être enregistré). En outre, l'utilisation des proxys de méthodes HTTP personnalisées pourrait déterminer leurs actions sans avoir besoin d'analyser le corps de l'entité.
C'est comme CRUD, vous voudriez toujours les implémenter, mais vous avez également votre propre ensemble spécifique d'actions (par entité). Je ne vois vraiment pas quel serait le problème pour les étendre.
Aussi @Rein Henrichs "Vous ne rédigez PAS un article, vous transformez son état de brouillon en vrai ou vous créez un brouillon de ressource" me semble faux. Une propriété drafts
serait utilisée pour sauvegarder l'état en permanence, pas pour effectuer la transformation. Les actions n'entraînent même pas nécessairement un "état" ou ne sont pas enregistrées dans une propriété. La création d'une entité distincte pour chaque état/transformation semble encore plus floue. Essayez de conserver la même référence (URI) à l'entité.