Quand utiliser les ressources imbriquées dans une API RESTful

16

J'ai deux ressources: les utilisateurs et les liens.

Les utilisateurs peuvent avoir plusieurs liens associés. J'ai conçu mon API RESTful pour que vous puissiez accéder aux liens associés à un utilisateur à l'URI suivant:

/users/:id/links

Cependant, j'ai toujours besoin d'un URI pour les liens uniquement - parfois, je peux vouloir tous les liens, quel que soit l'utilisateur.

Pour cela, j'ai:

/links

Cela vous semble-t-il correct? Vous avez deux URI pour les liens?

Je me demande si je devrais plutôt accéder aux liens d'un utilisateur avec un URI tel que:

/links/user/:id ou /links/?user=:id

De cette façon, je n'ai qu'une seule ressource pour les liens.

Oliver Joseph Ash
la source
3
hmm .. Celui-ci semble plus élégant:/links/user/:id
theMarceloR
7
@theMarceloR: C'est le seul exemple sur les trois que je ne trouve pas particulièrement clair. La ressource est-elle un lien ou un utilisateur? L'URI est beaucoup moins ambigu en utilisant la méthode des ressources imbriquées ( /users/:id/links) ou la méthode de la chaîne de requête ( /links/?user=:id) car il s'agit en fait d'une requête. /links/user/:idpeut sembler agréable et / ou être plus facile à router dans certains frameworks mais c'est en fait assez déroutant.
Aaronaught

Réponses:

16

Non, il n'y a rien de mal à avoir plusieurs ressources pour la même "chose", dans ce cas des listes de liens.

Nous étions récemment aux prises avec le même problème. Notre décision était d'avoir toutes les ressources là où il n'y a pas de propriété stricte pour ne pas être imbriquées. En d'autres termes, les liens seraient modélisés sous

/links -- all links
/links/:linkid -- a particular link

Ensuite, les filtres sur la collection de liens sont exprimés sous forme de paramètres de requête. Donc, pour obtenir les liens d'un certain utilisateur, vous utiliseriez:

/links?user=/users/:userid

Cela permet également une composition plus facile des filtres:

/links?user=/users/10&since=2013-01-01

Et il est facile à comprendre conceptuellement - vous avez une collection d'articles et vous y ajoutez des filtres.

Cela étant dit, il n'y a rien de plus "RESTful" dans cette approche que tout autre schéma de nommage d'URI. C'est juste une convention que nous avons trouvée lisible par l'homme et facile à comprendre pour les développeurs. REST ne se soucie pas de ce que vous mettez dans vos identificateurs de ressources.

jaseur
la source
1
«Toutes les ressources où il n'y a pas de propriété stricte pour ne pas être imbriquées» semblent être une bonne règle à avoir. Merci beaucoup.
Oliver Joseph Ash
5
Je dirais qu'il ya est quelque chose de mal à avoir de multiples ressources pour la même entité physique, mais ce n'est pas en fait ce que cela est. Chaque lien individuel a une URL canonique (links /: id), alors que chacune des ressources ci-dessus est en fait une ressource unique (/ links) avec des filtres appliqués. En outre, je suis bizarré par le ?user=users/:useriddans la chaîne de requête; quel est le problème avec juste ?userid=:userid?
Aaronaught
2
@Aaronaught: la raison de s'en tenir aux uri au lieu des identifiants nus est pour que les clients puissent traiter tous les identificateurs de ressources de manière égale, c'est-à-dire qu'un client doit seulement savoir que «cet utilisateur est identifié par "/*******"; où les *sont opaques. mais ce même identifiant peut toujours être utilisé pour faire référence à cette ressource (comme dans, avec des liens), pour récupérer la version la plus récente de cette ressource, etc. le contenu de cet uri n'est compris que par le serveur d'origine. Cela signifie également que si les identifiants doivent changer, par exemple /realm/:businessid/users/:id, le client ne change pas du tout.
SingleNegationElimination
@TokenMacGuy: Désolé, je ne comprends aucune partie de votre commentaire. Quelle est la différence pratique entre /users/:userid/linkset /links?userid=:userid? Dans les deux cas, les identifiants ne changent pas, ils récupèrent la version actuelle de cette ressource et le client les traite de la même manière. Il n'y a pas d'URL canonique pour cela car ce n'est pas une ressource, c'est une requête, donc ce ne sont que deux types différents de syntaxe de requête. Je ne sais pas non plus comment le client n'aurait pas besoin de changer si la structure de l'URL change; cela est considéré comme un changement de rupture dans REST à moins qu'un 301 ne soit en place.
Aaronaught
1
@Aaronaught: J'ai peut-être mal compris votre inquiétude. Supposons que /linksprend en charge une interface de requête, /links?user=/users/123permet une approche de boîte noire aux identificateurs de ressources dans les clients qui /links?userid=123ne le font pas. ce dernier exige que le client comprenne ce qu'est un ID utilisateur et comment l'obtenir, vraisemblablement à partir de la ressource qu'il a obtenue de /users/123ou /links/456/user. Le premier signifie que le client peut utiliser l'URI sans modification; en supposant que le /links/.../userdonne une réponse hypermédia (par exemple, avec des en- Location:têtes).
SingleNegationElimination
1

Donc, ma préoccupation est: / users /: userid / links renvoie "links", MAIS si le user_id n'est pas identifié, cela devrait retourner un 404.

pourtant

/ links? userid =: userid retournerait potentiellement une liste vide (essentiellement 200) qui est en fait probablement un bug. Et tout à fait possible.

Bien que les deux fonctionnent, l'imbrication vous offre des fonctionnalités supplémentaires que vous pourrez utiliser ultérieurement.

Richard Browne
la source