Supposons qu'une API REST, en réponse à une GET
requête HTTP , renvoie des données supplémentaires dans un sous-objet owner
:
{
id: 'xyz',
... some other data ...
owner: {
name: 'Jo Bloggs',
role: 'Programmer'
}
}
De toute évidence, nous ne voulons pas que quiconque puisse PUT
soutenir
{
id: 'xyz',
... some other data ...
owner: {
name: 'Jo Bloggs',
role: 'CEO'
}
}
et que cela réussisse. En effet, nous n'allons probablement même pas mettre en place un moyen pour que cela réussisse potentiellement, dans ce cas.
Mais cette question ne concerne pas seulement les sous-objets: que faut-il généralement faire avec des données qui ne devraient pas être modifiables dans une requête PUT?
Devrait-il être tenu de manquer de la demande PUT?
Devrait-il être jeté silencieusement?
Devrait-il être vérifié et, si elle diffère de l'ancienne valeur de cet attribut, renvoyer un code d'erreur HTTP dans la réponse?
Ou devrions-nous utiliser les correctifs JSON RFC 6902 au lieu d’envoyer l’ensemble du code JSON?
la source
Réponses:
Aucune règle, ni dans la spécification W3C ni dans les règles non officielles de REST, n'indique qu'un
PUT
doit utiliser le même schéma / modèle que celui correspondantGET
.C'est bien s'ils sont similaires , mais il n'est pas inhabituel
PUT
de faire les choses légèrement différemment. Par exemple, j'ai vu beaucoup d'API qui incluent une sorte d'identifiant dans le contenu renvoyé par unGET
, par souci de commodité. Mais avec aPUT
, cet ID est déterminé exclusivement par l'URI et n'a aucune signification dans le contenu. Toute identification trouvée dans le corps sera ignorée en silence.REST et le Web en général sont fortement liés au principe de robustesse : "Soyez conservateur dans ce que vous faites [envoyez], soyez libéral dans ce que vous acceptez." Si vous êtes d'accord philosophiquement avec cela, la solution est évidente: ignorez les données non valides dans les
PUT
demandes. Cela s'applique à la fois aux données immuables, comme dans votre exemple, et aux absurdités réelles, par exemple les champs inconnus.PATCH
C'est potentiellement une autre option, mais vous ne devriez pas l'implémenter àPATCH
moins de supporter des mises à jour partielles.PATCH
signifie seulement mettre à jour les attributs spécifiques que j'inclus dans le contenu ; cela ne signifie pas remplacer l'entité entière mais exclure certains champs spécifiques . Ce dont vous parlez en réalité n’est pas vraiment une mise à jour partielle, c’est une mise à jour complète, idempotente et tout, c’est simplement que cette partie de la ressource est en lecture seule.Une bonne chose à faire si vous choisissez cette option serait de renvoyer un 200 (OK) avec l'entité mise à jour dans la réponse, afin que les clients puissent clairement voir que les champs en lecture seule n'ont pas été mis à jour.
Il y a certainement des gens qui pensent autrement, que tenter de mettre à jour une partie en lecture seule d'une ressource devrait être une erreur. Cela peut être justifié, principalement parce que vous renverriez certainement une erreur si l' intégralité de la ressource était en lecture seule et que l'utilisateur tentait de la mettre à jour. Cela va certainement à l’encontre du principe de robustesse, mais vous pourriez le considérer comme plus "auto-documenté" par les utilisateurs de votre API.
Il existe deux conventions pour cela, qui correspondent toutes deux à vos idées originales, mais je les développerai davantage. La première consiste à empêcher les champs en lecture seule d'apparaître dans le contenu et à renvoyer un HTTP 400 (demande incorrecte) s'ils le font. Les API de ce type doivent également renvoyer un HTTP 400 s'il existe d'autres champs non reconnus / inutilisables. La seconde consiste à exiger que les champs en lecture seule soient identiques au contenu actuel et à renvoyer un 409 (conflit) si les valeurs ne correspondent pas.
Je n’aime vraiment pas le contrôle d’égalité avec 409 car il oblige invariablement le client à effectuer un
GET
test afin de récupérer les données actuelles avant de pouvoir effectuer un contrôlePUT
. Ce n'est tout simplement pas agréable et cela conduira probablement à de mauvaises performances, pour quelqu'un, quelque part. De plus, je n'aime vraiment pas 403 (interdit) car cela implique que la totalité de la ressource est protégée, pas seulement une partie de celle-ci. Donc, mon opinion est la suivante: si vous devez absolument valider au lieu de suivre le principe de robustesse, validez toutes vos demandes et renvoyez un 400 pour toutes celles comportant des champs supplémentaires ou non inscriptibles.Assurez-vous que votre 400/409 / what comprend des informations sur le problème spécifique et sur la façon de le résoudre.
Ces deux approches sont valables, mais je préfère la première, conformément au principe de robustesse. Si vous avez déjà travaillé avec une grande API REST, vous apprécierez la valeur de la compatibilité ascendante. Si vous décidez de supprimer un champ existant ou de le rendre en lecture seule, il s'agit d'une modification rétrocompatible si le serveur ignore simplement ces champs et que les anciens clients fonctionnent toujours. Toutefois, si vous appliquez une validation stricte au contenu, celui-ci n’est plus compatible avec les versions antérieures et les anciens clients ne fonctionneront plus. Le premier signifie généralement moins de travail pour le responsable d'une API et ses clients.
la source
Puissance idem
À la suite de la RFC, un PUT devrait fournir un objet complet à la ressource. La raison principale en est que PUT devrait être idempotent. Cela signifie qu'une demande répétée doit donner le même résultat sur le serveur.
Si vous autorisez les mises à jour partielles, cela ne peut plus être idem-puissant. Si vous avez deux clients. Client A et B, le scénario suivant peut évoluer:
Le client A obtient une image à partir d'images de ressources. Ceci contient une description de l'image, qui est toujours valide. Le client B met une nouvelle image et met à jour la description en conséquence. La photo a changé. Le client A voit, il n'a pas à changer la description, car c'est comme il veut et ne met que l'image.
Cela conduira à une incohérence, les mauvaises métadonnées attachées à l'image!
Encore plus ennuyeux, tout intermédiaire peut répéter la demande. Dans le cas où il décide d'une manière ou d'une autre, le PUT a échoué.
La signification de PUT ne peut pas être changée (bien que vous puissiez en abuser).
Autres options
Heureusement, il y a une autre option, c'est PATCH. PATCH est une méthode qui vous permet de mettre à jour partiellement une structure. Vous pouvez simplement envoyer une structure partielle. Pour des applications simples, c'est très bien. Cette méthode n'est pas garantie d'être idem puissant. Le client doit envoyer une demande sous la forme suivante:
Et le serveur peut répondre avec 204 (pas de contenu) pour signaler le succès. En cas d'erreur, vous ne pouvez pas mettre à jour une partie de la structure. La méthode PATCH est atomique.
L'inconvénient de cette méthode est que tous les navigateurs ne la prennent pas en charge, mais qu'il s'agit de l'option la plus naturelle dans un service REST.
Exemple de demande de correctif: http://tools.ietf.org/html/rfc5789#section-2.1
Json patcher
L'option json semble être assez complète et une option intéressante. Mais il peut être difficile à mettre en œuvre pour des tiers. Vous devez décider si votre base d'utilisateurs peut gérer cela.
Il est également un peu compliqué, car vous devez créer un petit interpréteur qui convertit les commandes en une structure partielle, que vous allez utiliser pour mettre à jour votre modèle. Cet interpréteur doit également vérifier si les commandes fournies ont un sens. Certaines commandes s'annulent. (écrivez fielda, supprimez fielda). Je pense que vous souhaitez signaler cela au client pour limiter le temps de débogage de son côté.
Mais si vous avez le temps, c'est une solution vraiment élégante. Vous devez encore valider les champs de cours. Vous pouvez combiner cela avec la méthode PATCH pour rester dans le modèle REST. Mais je pense que POST serait acceptable pour ici.
Aller mal
Si vous décidez d’utiliser l’option PUT, vous risquez un peu. Dans ce cas, vous devriez au moins ne pas supprimer l’erreur. L'utilisateur a une certaine attente (les données seront mises à jour) et si vous cassez cela, vous allez donner du temps à certains développeurs.
Vous pouvez choisir de signaler: 409 Conflict ou 403 Forbidden. Cela dépend comment vous regardez le processus de mise à jour. Si vous le voyez comme un ensemble de règles (centré sur le système), alors le conflit sera plus agréable. Quelque chose comme, ces champs ne peuvent pas être mis à jour. (En conflit avec les règles). Si vous le voyez comme un problème d’autorisation (centré sur l’utilisateur), vous devriez alors renvoyer interdit. Avec: vous n'êtes pas autorisé à modifier ces champs.
Vous devez toujours obliger les utilisateurs à envoyer tous les champs modifiables.
Une option raisonnable pour le faire est de le définir sur une sous-ressource, qui ne propose que les données modifiables.
Opinion personnelle
Personnellement, j'irais (si vous n'avez pas à travailler avec des navigateurs) pour le modèle PATCH simple, puis étendez-le plus tard avec un processeur de patch JSON. Cela peut être fait en différenciant les types MIME: Le type MIME de JSON Patch:
application / json-patch
Et json: application / json-patch
facilite sa mise en œuvre en deux phases.
la source