web-dev-qa-db-fra.com

Pour inclure un ID de ressource dans la charge utile ou pour dériver de l'URI

En concevant une API, nous nous sommes heurtés à la question de savoir si une charge utile PUT doit contenir l'ID de la ressource mise à jour.

Voici ce que nous avons actuellement:

PUT /users/123 Payload: {name: "Adrian"}

Notre code d'itinéraire extrait l'ID de l'URI et continue la mise à jour.

Les premiers utilisateurs de notre API se demandent pourquoi nous n'autorisons pas l'ID dans la charge utile:

PUT /users/123 Payload: {id: 123, name: "Adrian"}

La raison pour laquelle nous ne l'avons pas autorisé est que l'ID est dupliqué, dans la charge utile et l'URI.

En y réfléchissant un peu plus, nous couplons la ressource à l'URI.

Si l'URI n'a pas l'ID, la charge utile devra être modifiée:

PUT /no/id/here Payload: {name: "Adrian"} < What user???

Y a-t-il des raisons de ne pas le faire?

13
Adrian Lynch

Vous êtes censé coupler l'identificateur de l'uniforme ressource au ressource.

Lorsque REST est implémenté avec HTTP, vous utilisez GET pour récupérer la valeur actuelle de la ressource et PUT pour définir une nouvelle valeur. Le GET n'a pas de charge utile, donc la ressource doit être identifiée par l'URI. Et le PUT est logiquement effectué sur le même URI et la charge utile doit ressembler exactement à ce que vous voulez que le prochain GET renvoie.

Vous pouvez utiliser POST vers différents URI, mais cela n'aurait que moins de sens car il serait inutilement asymétrique par rapport à GET. POST vers des URI communs ne pourrait que faire sens pour créer de nouvelles ressources (POST /users/new, charge utile: {name: "Adrian"}, réponse {id: 345, name: "Adrian"}), mais ce n'est pas idempotent et donc à éviter si vous cherchez REST¹. Au lieu de cela, vous devez réserver l'ID avec un seul appel, puis utiliser PUT pour définir le nouvel ID; cela est tolérant aux pannes, car si la première demande échoue, la réservation d'ID peut éventuellement expirer et le PUT est idempotent. Ou utilisez l'UUID généré par le client.


¹ La définition de REST ne dit rien sur l'idempotence, donc je ne peux pas vraiment affirmer que ce n'est pas REST si vous avez des opérations non idempotentes. ne change pas le fait que s'en tenir aux demandes idempotentes rend les choses plus fiables sans les compliquer et est donc recommandé.

14
Jan Hudec

En y réfléchissant un peu plus, nous couplons la ressource à l'URI.

Si l'URI n'a pas l'ID, la charge utile devra être modifiée:

PUT/no/id/here Charge utile: {nom: "Adrian"} <Quel utilisateur ???

Y a-t-il des raisons de ne pas le faire?

La réponse à cette question dépend de si vous souhaitez autoriser le client à modifier l'ID?

Si le client peut modifier l'ID, via un PUT, l'URI de la ressource changera, et vous devez fournir un 301 déplacé de façon permanente à chaque fois qu'une ressource accède à l'ancien URI.

Ainsi, par exemple, vous commencez avec une ressource à

/users/123

et le client met ce qui suit sur la ressource

{id: 222, name: "Adrian"}

la ressource a été mise à jour et son URI est maintenant

/users/222

Le champ Location dans la réponse PUT doit contenir le nouvel URI, et si vous allez dans /users/123 vous devriez obtenir un 301 réponse avec le champ Emplacement pointant vers le nouveau /users/222 Ressource.

Dans la plupart des cas, vous ne voulez pas que le client puisse changer l'ID, car cela peut devenir assez compliqué assez rapidement. Dans ce cas, l'ID est quelque chose que seul le serveur peut changer, et vous devez le laisser hors du corps PUT, car le client ne peut pas mettre à jour cet état.

Si vous METTEZ un besoin vers un URI différent sur la même ressource, dites

/users/adian_lync

alors si cette ressource n'existe pas, le serveur doit la créer et créer et ID quand il le fait

2
Cormac Mulhall