2009-09-15 9 views
19

J'ai une ressource qui a un compteur. Par souci d'exemple, nous appellerons la ressource profil, et le compteur est le nombre de vues pour ce profil.Incrémentation du compteur de ressources d'une manière RESTful: PUT vs POST

Par le REST wiki, les requêtes PUT doivent être utilisées pour la création ou la modification de ressources et doivent être idempotentes. Cette combinaison est bonne si je mets à jour, disons, le nom du profil, parce que je peux émettre une requête PUT qui définit le nom à quelque chose 1000 fois et le résultat ne change pas.

Pour ces demandes standard PUT, j'ai les navigateurs font quelque chose comme:

PUT /profiles/123?property=value&property2=value2 

Pour incrémenter un compteur, on appelle l'URL comme ceci:

PUT /profiles/123/?counter=views 

Chaque appel entraînera le compteur être incrémenté. Techniquement, c'est une opération de mise à jour, mais elle viole l'idempotence.

Je suis à la recherche de conseils/meilleures pratiques. Faites-vous juste cela comme un POST?

Répondre

8

Une alternative pourrait être d'ajouter une autre ressource au système pour suivre les vues d'un profil. Vous pourriez l'appeler "Viewing".

Pour voir tous visionnements d'un profil:

GET/profils/123/visionnages

Pour ajouter un affichage à un profil:

POST/profils/123/visionnages #Ici, vous 'd soumettez les détails en utilisant un type de média personnalisé dans le corps de la requête.

Pour mettre à jour une visualisation existante:

PUT/visionnages/815 # attributs submit Refondu de la visualisation dans le corps de la demande en utilisant le type de support personnalisé que vous avez créé.

Pour naviguer dans les détails d'une vision:

GET/visionnages/815

Pour supprimer un Viewing:

SUPPRIMER/visionnages/815

Aussi, parce que vous re demandant des meilleures pratiques, assurez-vous que votre système RESTful est hypertext-driven. Pour la plupart, il n'y a rien de mal à utiliser les paramètres de requête dans les URI - ne donnez pas à vos clients l'idée qu'ils peuvent les manipuler. Au lieu de cela, créez un type de support qui incarne les concepts que les paramètres tentent de modéliser. Donnez à ce type de média un nom concis, non ambigu et descriptif. Puis documentez ce type de média. Le vrai problème de l'exposition des paramètres de requête dans REST est que la pratique entraîne souvent une communication hors bande, et donc un couplage accru entre le client et le serveur.

Ensuite, donnez à votre système une interface uniforme. Par exemple, l'ajout d'une nouvelle ressource est toujours un POST. La mise à jour d'une ressource est toujours un PUT. La suppression est DELETE, et getiing est GET. La partie la plus difficile à propos de REST est de comprendre comment les types de médias se retrouvent dans la conception du système (c'est aussi la partie que Fielding a omis de sa thèse parce qu'il a manqué de temps). Si vous voulez un exemple spécifique d'un système piloté par hypertexte qui utilise et types de médias doucuments, voir le Sun Cloud API.

+0

Juste pour clarifier:/viewings/815 fait référence à la 815ème visualisation d'un profil, oui? –

9

Je pense que la bonne réponse est d'utiliser PATCH. Je ne l'ai pas vu personne recommandant d'autre, il devrait être utilisé pour incrémenter atomiquement un compteur, mais je crois RFC 2068 le dit très bien:

La méthode PATCH est similaire à PUT, sauf que l'entité contient une liste de différences entre la version originale de la ressource identifiée par l'URI de demande et le contenu souhaité de la ressource après l'application de l'action PATCH. La liste des différences est dans un format défini par le type de média de l'entité (par exemple, "application/diff") et DOIT inclure suffisamment d'informations pour permettre au serveur de recréer les modifications nécessaires pour convertir la version originale du ressource à la version souhaitée.

Ainsi, pour mettre à jour le profil 123 le nombre de vue, je voudrais:

PATCH /profiles/123 HTTP/1.1 
Host: www.example.com 
Content-Type: application/x-counters 

views + 1 

Lorsque le type x-counters des médias (que je viens d'inventer) est faite de plusieurs lignes de field operator scalar tuples. views = 500 ou views - 1 ou views + 3 sont tous valables syntaxiquement (mais peuvent être interdits sémantiquement).

Je peux comprendre un peu de froncement de maquiller un autre type de support, mais je suggère humblement que c'est plus correct que l'alternative POST/PUT. Faire une ressource pour un champ, compléter avec son propre URI et surtout ses propres détails (que je ne garde pas vraiment, tout ce que j'ai est un entier) me semble mauvais et lourd. Que faire si j'ai 23 compteurs différents à entretenir?

+1

Dévient de la norme un petit bit parce qu'il n'a pas "le contenu désiré de la ressource après que l'action PATCH a été appliquée". Par exemple. l'entité est une instruction à exécuter, pas le résultat souhaité. – Pocketsand

+0

À la suite de ce qu'a dit @Pocketsand, cette approche ne viole-t-elle pas la sous-contrainte «Manipulation des ressources par les représentations» sous la contrainte «Uniform Interface»? Où vous devriez renvoyer une représentation de la ressource que vous voulez voir, au lieu d'envoyer des instructions sur la façon de la manipuler. – dayuloli

+0

@dayuloli Si vous envisagez toujours une solution, j'ai [ajouté une réponse] (https://stackoverflow.com/questions/1426845/incrementing-resource-counter-in-a-restful-way-put-vs-post/44852115 # 44852115) avec ce que j'ai décidé d'aller avec, cela peut ou peut convenir à vos besoins. – Pocketsand

0

Je pense que les deux approches de Yanic et Rich sont interressantes. Un PATCH n'a pas besoin d'être sûr ou indempotent mais peut être dans le but d'être plus robuste contre la concurrence. La solution de Rich est certainement plus facile à utiliser dans une API REST "standard".

Voir RFC5789:

PATCH est ni sûr ni idempotent tel que défini par [RFC2616], section 9.1 .

Une demande PATCH peut être émis de telle manière à être idempotent, qui contribue également à prévenir les mauvais résultats de collisions entre deux demandes PATCH sur la même ressource dans un laps de temps similaire. Les collisions provenant de plusieurs demandes PATCH peuvent être plus dangereuses que les collisions PUT parce que certains formats de patch doivent fonctionner à partir d'un point de base connu , sinon ils corrompent la ressource.

0

Après avoir évalué les réponses précédentes, j'ai décidé PATCH était inappropriée et, pour mes fins, bidouiller avec Content-Type pour une tâche triviale était une violation de la KISS principle. Je ne avais besoin d'incrémenter n + 1, donc je viens de faire ceci:

PUT /profiles/123$views 
++ 

++ est le corps du message et est interprété par le contrôleur comme une instruction pour augmenter la ressource par un.

J'ai choisi $ à DÉliminer le terrain/propriété de la ressource comme il est un legal sub-delimiter et, pour mes fins, semblait plus intuitive que / qui, à mon avis, a l'ambiance de la pénétrabilité.

Questions connexes