J'écris un service RESTful pour un système de gestion client et j'essaie de trouver la meilleure pratique pour mettre à jour les enregistrements partiellement. Par exemple, je veux que l'appelant puisse lire l'enregistrement complet avec une demande GET. Mais pour le mettre à jour, seules certaines opérations sur l'enregistrement sont autorisées, comme changer l'état de ENABLED à DISABLED. (J'ai des scénarios plus complexes que cela)
Je ne veux pas que l'appelant soumette l'intégralité de l'enregistrement avec uniquement le champ mis à jour pour des raisons de sécurité (cela semble également exagéré).
Existe-t-il un moyen recommandé de construire les URI? Lors de la lecture des livres REST, les appels de style RPC semblent être désapprouvés.
Si l'appel suivant renvoie l'enregistrement client complet pour le client avec l'ID 123
GET /customer/123
<customer>
{lots of attributes}
<status>ENABLED</status>
{even more attributes}
</customer>
comment dois-je mettre à jour le statut?
POST /customer/123/status
<status>DISABLED</status>
POST /customer/123/changeStatus
DISABLED
...
Mise à jour : pour augmenter la question. Comment intégrer des «appels de logique métier» dans une API REST? Existe-t-il une façon convenue de procéder? Toutes les méthodes ne sont pas CRUD par nature. Certains sont plus complexes, comme « sendEmailToCustomer (123) », « mergeCustomers (123, 456) », « countCustomers () »
POST /customer/123?cmd=sendEmail
POST /cmd/sendEmail?customerId=123
GET /customer/count
POST
de Roy Fielding lui-même: roy.gbiv.com/untangled/2009/it-is-okay-to-use-post où l'idée de base est: s'il n'y en a pas 't une méthode (commeGET
ouPUT
) idéalement adaptée à votre utilisation opérationnellePOST
.Réponses:
Vous avez essentiellement deux options:
Utiliser
PATCH
(mais notez que vous devez définir votre propre type de média qui spécifie ce qui se passera exactement)Utilisez
POST
une ressource secondaire et renvoyez 303 Voir Autre avec l'en-tête Location pointant vers la ressource principale. L'intention du 303 est de dire au client: "J'ai effectué votre POST et l'effet a été qu'une autre ressource a été mise à jour. Voir l'en-tête Emplacement pour quelle ressource c'était." POST / 303 est destiné aux ajouts itératifs à des ressources pour construire l'état de certaines ressources principales et il convient parfaitement aux mises à jour partielles.la source
Vous devez utiliser POST pour les mises à jour partielles.
Pour mettre à jour les champs du client 123, effectuez un POST vers / client / 123.
Si vous souhaitez mettre à jour uniquement le statut, vous pouvez également METTRE / client / 123 / statut.
Généralement, les requêtes GET ne devraient pas avoir d'effets secondaires, et PUT sert à écrire / remplacer la ressource entière.
Cela découle directement de HTTP, comme on le voit ici: http://en.wikipedia.org/wiki/HTTP_PUT#Request_methods
la source
/customer/123
devrait créer la chose évidente qui est logiquement sous le client 123. Peut-être une commande? PUT/customer/123/status
semble avoir un meilleur sens, en supposant que le POST a/customers
implicitement créé unstatus
(et en supposant que c'est REST légitime).POST
demandes n'ont pas besoin d'être non idempotentes. Et comme mentionné,PUT
doit remplacer une ressource entière.Vous devez utiliser PATCH pour les mises à jour partielles - soit en utilisant des documents json-patch (voir http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-08 ou http://www.mnot.net/ blog / 2012/09/05 / patch ) ou le framework de correctifs XML (voir http://tools.ietf.org/html/rfc5261 ). À mon avis, json-patch est le mieux adapté à votre type de données d'entreprise.
PATCH avec des documents de patch JSON / XML a une sémantique très étroite pour les mises à jour partielles. Si vous commencez à utiliser POST, avec des copies modifiées du document d'origine, pour les mises à jour partielles, vous rencontrez rapidement des problèmes où vous souhaitez que les valeurs manquantes (ou plutôt les valeurs nulles) représentent soit "ignorer cette propriété", soit "définir cette propriété sur le valeur vide "- et cela mène à un trou de lapin de solutions piratées qui se traduira finalement par votre propre type de format de patch.
Vous pouvez trouver une réponse plus approfondie ici: http://soabits.blogspot.dk/2013/01/http-put-patch-or-post-partial-updates.html .
la source
Je rencontre un problème similaire. PUT sur une sous-ressource semble fonctionner lorsque vous souhaitez mettre à jour un seul champ. Cependant, parfois, vous souhaitez mettre à jour un tas de choses: pensez à un formulaire Web représentant la ressource avec l'option de modifier certaines entrées. La soumission du formulaire par l'utilisateur ne doit pas entraîner plusieurs PUT.
Voici deux solutions auxquelles je peux penser:
faire un PUT avec la ressource entière. Côté serveur, définissez la sémantique qu'un PUT avec la ressource entière ignore toutes les valeurs qui n'ont pas changé.
faire un PUT avec une ressource partielle. Côté serveur, définissez la sémantique de ceci comme une fusion.
2 est juste une optimisation de la bande passante de 1. Parfois, 1 est la seule option si la ressource définit certains champs sont des champs obligatoires (pensez proto tampons).
Le problème avec ces deux approches est de savoir comment effacer un champ. Vous devrez définir une valeur nulle spéciale (en particulier pour les tampons de prototypage puisque les valeurs nulles ne sont pas définies pour les tampons de prototypage) qui entraîneront l'effacement du champ.
Commentaires?
la source
Pour modifier l'état, je pense qu'une approche RESTful consiste à utiliser une sous-ressource logique qui décrit l'état des ressources. Cet IMO est assez utile et propre lorsque vous avez un ensemble réduit de statuts. Il rend votre API plus expressive sans forcer les opérations existantes pour votre ressource client.
Exemple:
Le service POST doit renvoyer le client nouvellement créé avec l'ID:
Le GET pour la ressource créée utiliserait l'emplacement de la ressource:
Un GET / client / 123 / inactif doit retourner 404
Pour l'opération PUT, sans fournir d'entité Json, il suffit de mettre à jour l'état
Fournir une entité vous permettra de mettre à jour le contenu du client et de mettre à jour le statut en même temps.
Vous créez une sous-ressource conceptuelle pour votre ressource client. Elle est également cohérente avec la définition de Roy Fielding d'une ressource: "... Une ressource est un mappage conceptuel avec un ensemble d'entités, pas l'entité qui correspond au mappage à un moment donné dans le temps ..." Dans ce cas, le le mappage conceptuel est actif-client à client avec le statut = ACTIF.
Opération de lecture:
Si vous effectuez ces appels l'un après l'autre, l'autre doit renvoyer l'état 404, la sortie réussie peut ne pas inclure l'état car il est implicite. Bien sûr, vous pouvez toujours utiliser GET / customer / 123? Status = ACTIVE | INACTIVE pour interroger directement la ressource client.
L'opération DELETE est intéressante car la sémantique peut être déroutante. Mais vous avez la possibilité de ne pas publier cette opération pour cette ressource conceptuelle, ou de l'utiliser conformément à votre logique métier.
Celui-ci peut amener votre client à un statut SUPPRIMÉ / HANDICAPÉ ou au statut opposé (ACTIF / INACTIF).
la source
Choses à ajouter à votre question augmentée. Je pense que vous pouvez souvent parfaitement concevoir des actions commerciales plus compliquées. Mais vous devez abandonner le style de pensée de la méthode / procédure et réfléchir davantage aux ressources et aux verbes.
envois de courrier
L'implémentation de cette ressource + POST enverrait alors le courrier. si nécessaire, vous pouvez alors proposer quelque chose comme / customer / 123 / outbox, puis proposer des liens de ressources vers / customer / mails / {mailId}.
nombre de clients
Vous pouvez le gérer comme une ressource de recherche (y compris des métadonnées de recherche avec pagination et informations trouvées sur le nombre, ce qui vous donne le nombre de clients).
la source
Utilisez PUT pour mettre à jour une ressource incomplète / partielle.
Vous pouvez accepter jObject comme paramètre et analyser sa valeur pour mettre à jour la ressource.
Voici la fonction que vous pouvez utiliser comme référence:
la source
Concernant votre mise à jour.
Je crois que le concept de CRUD a causé une certaine confusion concernant la conception des API. CRUD est un concept général de bas niveau pour les opérations de base à effectuer sur les données, et les verbes HTTP ne sont que des méthodes de demande ( créé il y a 21 ans ) qui peuvent ou non correspondre à une opération CRUD. En fait, essayez de trouver la présence de l'acronyme CRUD dans la spécification HTTP 1.0 / 1.1.
Un guide très bien expliqué qui applique une convention pragmatique se trouve dans la documentation de l'API Google Cloud Platform . Il décrit les concepts derrière la création d'une API basée sur les ressources, qui met l'accent sur une grande quantité de ressources par rapport aux opérations, et inclut les cas d'utilisation que vous décrivez. Bien que ce soit juste une conception conventionnelle pour leur produit, je pense que cela a beaucoup de sens.
Le concept de base ici (et qui produit beaucoup de confusion) est le mappage entre les "méthodes" et les verbes HTTP. Une chose est de définir quelles "opérations" (méthodes) votre API fera sur quels types de ressources (par exemple, obtenir une liste de clients ou envoyer un e-mail), et une autre sont les verbes HTTP. Il doit y avoir une définition des deux, les méthodes et les verbes que vous prévoyez d'utiliser et un mappage entre eux .
Il dit aussi que, lorsqu'une opération ne correspond pas exactement à une méthode standard (
List
,Get
,Create
,Update
,Delete
dans ce cas), on peut utiliser des « méthodes personnalisées », commeBatchGet
, qui récupère plusieurs objets en fonction de plusieurs entrées identifiant d'objet ouSendEmail
.la source
RFC 7396 : JSON Merge Patch (publié quatre ans après la publication de la question) décrit les meilleures pratiques pour un PATCH en termes de format et de règles de traitement.
En bref, vous soumettez un PATCH HTTP à une ressource cible avec le type de média application / merge-patch + json MIME et un corps représentant uniquement les parties que vous souhaitez modifier / ajouter / supprimer, puis suivez les règles de traitement ci-dessous.
Règles :
Exemples de cas de test qui illustrent les règles ci-dessus (comme vu dans l' annexe de ce RFC):
la source
Consultez http://www.odata.org/
Il définit la méthode MERGE, donc dans votre cas, ce serait quelque chose comme ceci:
Seule la
status
propriété est mise à jour et les autres valeurs sont conservées.la source
MERGE
verbe HTTP est -il valide?MERGE was used to do PATCH before PATCH existed. Now that we have PATCH, we no longer need MERGE.
Voir docs.oasis-open.org/odata/new-in-odata/v4.0/cn01/…Ça n'a pas d'importance. En termes de REST, vous ne pouvez pas faire de GET, car il n'est pas mis en cache, mais peu importe si vous utilisez POST ou PATCH ou PUT ou autre chose, et peu importe à quoi ressemble l'URL. Si vous faites REST, ce qui importe, c'est que lorsque vous obtenez une représentation de votre ressource à partir du serveur, cette représentation est en mesure de donner au client des options de transition d'état.
Si votre réponse GET comportait des transitions d'état, le client a juste besoin de savoir comment les lire et le serveur peut les modifier si nécessaire. Ici, une mise à jour est effectuée à l'aide de POST, mais si elle a été modifiée en PATCH, ou si l'URL change, le client sait toujours comment effectuer une mise à jour:
Vous pouvez aller jusqu'à lister les paramètres obligatoires / facultatifs que le client vous rendra. Cela dépend de l'application.
En ce qui concerne les opérations commerciales, il peut s'agir d'une ressource différente liée à la ressource client. Si vous souhaitez envoyer un e-mail au client, ce service est peut-être sa propre ressource vers laquelle vous pouvez POSTER, vous pouvez donc inclure l'opération suivante dans la ressource client:
Voici de bonnes vidéos et un exemple de l'architecture REST du présentateur. Stormpath utilise uniquement GET / POST / DELETE, ce qui est bien car REST n'a rien à voir avec les opérations que vous utilisez ou l'apparence des URL (sauf que les GET doivent pouvoir être mis en cache):
https://www.youtube.com/watch?v=pspy1H6A3FM ,
https://www.youtube.com/watch?v=5WXYw4J4QOU ,
http://docs.stormpath.com/rest/quickstart/
la source