Quel est le meilleur modèle pour ajouter un élément existant à une collection dans l'API REST?

23

Je conçois une API REST pragmatique et je suis un peu coincé sur la meilleure façon d'ajouter des entités existantes à une collection. Mon modèle de domaine comprend un projet qui possède une collection de sites. Il s'agit d'une stricte relation plusieurs-à-plusieurs et je n'ai pas besoin de créer une entité qui modélise explicitement la relation (c'est-à-dire ProjectSite).

Mon API permettra aux consommateurs d'ajouter un site existant à un projet. Là où je me bloque, c'est que les seules données dont j'ai vraiment besoin sont ProjectId et SiteId. Mon idée initiale était:

1. POST myapi/projects/{projectId}/sites/{siteId}

Mais j'ai aussi pensé à

2. POST myapi/projects/{projectId}/sites

avec une entité Site envoyée en tant que contenu JSON.

L'option 1 est simple et fonctionne mais ne semble pas tout à fait correcte, et j'ai d'autres relations qui ne peuvent pas suivre ce modèle, ce qui ajoute une incohérence à mon API.

L'option 2 se sent mieux mais conduit à deux préoccupations:

  • Dois-je créer un site ou lever une exception si un nouveau site est publié (SiteId = 0)?
  • Étant donné que je n'ai besoin que de ProjectId et SiteId pour créer la relation, le site peut être publié avec des données incorrectes ou manquantes pour d'autres propriétés.

Une troisième option consiste à fournir un point de terminaison simple uniquement pour créer et supprimer la relation. Ce point de terminaison attendrait une charge utile JSON contenant uniquement ProjectId et SiteId.

Qu'est-ce que tu penses?

Jamie Ide
la source
2
Voir aussi: stackoverflow.com/questions/2001773/…
Rory Hunter
@RoryHunter Il y a une discussion intéressante dans ce lien mais rien qui n'élimine mon incertitude. J'aime particulièrement que la réponse acceptée indique "Vous avez bien compris". et la 2e place (quoique dans une large mesure) répond "Simplement dit, vous faites cela complètement à l'envers."
Jamie Ide
Votre première option est très bien, mais j'utiliserais PUT au lieu de POST car le client contrôle l'identité ajoutée à la collection. Votre première préoccupation avec l'option 2 est entièrement de votre ressort, si vous ne voulez pas de nouveaux sites, ne lancez pas d'exception mais renvoyez l'un des codes 4xx. Votre deuxième préoccupation n'est ni ici ni là. De toute façon, vous ne devriez pas publier un site entier, sauf si vous autorisez des ajouts. L'ajout d'un site existant doit avoir l'ID uniquement lorsque vous modifiez le site, mais uniquement la collection "ProjectSite" (même si vous ne créez pas de ressource distincte pour celui-ci).
Marjan Venema

Réponses:

14

POST est le verbe "append", ainsi que le verbe "processing". PUT est le verbe "créer / mettre à jour" (pour les identificateurs connus), et ressemble presque au bon choix ici, car l'URI cible complet est connu. projectIdet siteIdexistent déjà, vous n'avez donc pas besoin de "POST vers une collection" pour produire un nouvel ID.

Le problème avec PUT est qu'il requiert que le corps soit la représentation de la ressource que vous PUTtez. Mais l'intention ici est d'ajouter à la ressource de collection "projet / sites", plutôt que de mettre à jour la ressource Site.

Et si quelqu'un met une représentation JSON complète d'un site existant? Devez-vous mettre à jour la collection et mettre à jour l'objet? Vous pourriez soutenir cela, mais il semble que ce ne soit pas l'intention. Comme tu dis,

les seules données dont j'ai vraiment besoin sont ProjectId et SiteId

Au lieu de cela, j'essayerais de POSTER le siteIddans la collection, et je compterais sur la nature "ajouter" et "traiter" de POST:

POST myapi / projets / {projectId} / sites

{'id': '...'}

Puisque vous modifiez la ressource de collection de sites et non la ressource de site , c'est l'URI que vous souhaitez. POST peut savoir «ajouter / traiter» et ajouter l'élément avec cet identifiant à la collection de sites du projet.

Cela laisse toujours la porte ouverte à la création de nouveaux sites pour le projet en étoffant le JSON et en omettant l'identifiant. "No id" == "créer à partir de zéro". Mais si l'URI de collection obtient un identifiant et rien d'autre, il est assez clair ce qui doit se produire.

Question interessante. :)

Rob
la source
Je suis de la croyance qui croit que POST est pour créer et PUT est pour mise à jour mais votre conclusion est là où je me suis retrouvé hier. La bonne chose est que grâce au routage d'attributs dans l'API Web, j'ai le code dans un contrôleur ProjectSites donc le code est bien organisé.
Jamie Ide
Je pense que la raison principale que vous devez utiliser à la POSTplace PUTou PATCHici est que vous n'avez pas l' Siteentité entière à mettre dans la sitesressource. Vous n'avez que l'ID, ce qui nécessite un traitement pour l'ajouter à la collection.
écraser le
4

Nous utilisons la Patchméthode pour des trucs comme ça. Ce que vous voulez faire, c'est modifier un projet existant pour y ajouter un site.

Donc, quelque chose comme ça fonctionnerait

PATCH myapi/projects/{id} 

avec l'entité Site (s) en tant que JSON / JSONArray dans le corps de la demande.

De cette façon, vous pouvez utiliser la même URL pour modifier différentes parties du projet si vous en avez besoin - votre code dans l'implémentation doit être suffisamment intelligent pour gérer cette modification partielle de la ressource.

juan
la source
Approche intéressante. J'ai un modèle de domaine plus ancien "riche" (c'est-à-dire très dépendant) et Project a surtout de nombreuses collections qui l'accrochent. Détecter le type d'entité figurant dans la demande serait un défi et ne correspond pas à mon objectif pragmatique.
Jamie Ide
Pourquoi un défi? Si vous avez ces restrictions, vous pouvez toujours utiliser un JSON qui rend explicite ce qu'il envoie ... comme {"sites": [], "other-stuff": {}}, vous pouvez ensuite brancher votre code pour gérer tous ces "subjsons" très facilement. Cela dépend vraiment de votre problème spécifique, mais je recommanderais toujours d'utiliser PATCH car il est conçu spécifiquement pour ce genre de choses.
juan
Les inconvénients que je vois sont 1) l'API ne communique pas explicitement quelles collections autorisent les changements; 2) ne peut pas tirer parti de la liaison des paramètres de l'API Web; 3) gros interrupteur ou instruction if.
Jamie Ide
Je n'ai jamais vu la méthode du patch utilisée ailleurs
NimChimpsky
Ne vous PATCHattendriez -vous pas également à ce que l'entité complète soit transmise comme sa valeur ici, plutôt que comme un identifiant qui pointe vers une entité?
écraser le