CONCEPTION D'API REST - Obtenir une ressource via REST avec des paramètres différents mais le même modèle d'URL

92

J'ai une question relative à la conception de l'URL REST. J'ai trouvé quelques articles pertinents ici: Différentes représentations RESTful de la même ressource et ici: URL RESTful pour GET ressource par différents champs mais les réponses ne sont pas tout à fait claires sur les meilleures pratiques et pourquoi. Voici un exemple.

J'ai des URL REST pour représenter la ressource "utilisateurs". Je peux OBTENIR un utilisateur avec un identifiant ou une adresse e-mail, mais la représentation de l'URL reste la même pour les deux. En parcourant beaucoup de blogs et de livres, je constate que les gens font cela de différentes manières. Par exemple

lire cette pratique dans un livre et quelque part sur stackoverflow (je n'arrive pas à retrouver le lien)

GET /users/id={id}
GET /users/email={email}

lisez cette pratique sur de nombreux blogs

GET /users/{id}
GET /users/email/{email}

Les paramètres de requête sont normalement utilisés pour filtrer les résultats des ressources représentées par l'url, mais j'ai également vu cette pratique être utilisée

GET /users?id={id}
GET /users?email={email}

Ma question est, parmi toutes ces pratiques, laquelle serait la plus logique pour les développeurs qui utilisent les API et pourquoi? Je pense qu'il n'y a pas de règles gravées dans le marbre en ce qui concerne les conceptions d'URL REST et les conventions de dénomination, mais je voulais juste savoir quelle route je devrais emprunter pour aider les développeurs à mieux comprendre les API.

Toute l'aide appréciée!

shahshi15
la source
1
Je sais que c'est un peu vieux, mais à la recherche de ressources similaires, je tombe sur cette question et celle que vous recherchiez. Je crois que c'est celui-ci stackoverflow.com/a/9743414/468327
Joel Berger

Réponses:

102

D'après mon expérience, GET /users/{id} GET /users/email/{email}c'est l'approche la plus courante. Je m'attendrais également à ce que les méthodes retournent un 404 Not Found si un utilisateur n'existe pas avec le fichier idou email. Je ne serais pas surpris de voir GET /users/id/{id}non plus (même si à mon avis, c'est redondant).

Commentaires sur les autres approches

  1. GET /users/id={id} GET /users/email={email}
    • Je ne pense pas avoir vu cela, et si je le voyais, ce serait très déroutant. C'est presque comme s'il essayait d'imiter les paramètres de requête avec des paramètres de chemin.
  2. GET /users?id={id} GET /users?email={email}
    • Je pense que vous avez frappé dans le mille lorsque vous avez mentionné l'utilisation de paramètres de requête pour le filtrage.
    • Serait-il jamais judicieux d'appeler cette ressource à la fois avec un idet un email(par exemple GET /users?id={id}&email={email})? Sinon, je n'utiliserais pas une seule méthode de ressource comme celle-ci.
    • Je pense cette méthode pour récupérer une liste d'utilisateurs avec des paramètres de la requête en option pour le filtrage, mais je ne serais pas attendre id, emailou un identifiant unique d'être parmi les paramètres. Par exemple: GET /users?status=BANNEDpeut renvoyer une liste d'utilisateurs interdits.

Découvrez cette réponse à une question connexe.

DannyMo
la source
Merci de votre contribution. En fait, vous avez raison. Il semble que j'ai lu le n ° 1 dans le livre "RESTful java with Jax-rs" mais quelque peu hors contexte. Mais je me souviens très clairement avoir lu cela comme une réponse à l'une des questions sur le stackoverflow lui-même (croyez-moi quand je dis que j'essaie très fort de trouver ce lien à prouver à mes collègues aussi :)) et le n ° 2 est exactement ce que j'étais à la recherche de. Quelques retours sur le design. Je vous remercie!
shahshi15
PS: Je ne sais pas si publier ceci est contraire à la règle ici mais vous pouvez probablement jeter un peu de lumière sur l'une de mes autres questions également? S'il vous plaît? :) stackoverflow.com/questions/20508008/…
shahshi15
juste pour clarifier votre déclaration de redondance car /users/id/{id}, cela permet une fonctionnalité étendue, permet simplement d'accéder à une ressource via plusieurs identifiants (id, guid, nom). a également répondu ici
Daniel Dubovski
4
Ma réponse serait que la manière appropriée de référencer un utilisateur spécifique par exemple serait / users / {id}. Si vous vouliez trouver des utilisateurs par une adresse e-mail particulière qui n'est pas l'identifiant unique des utilisateurs que je ferais / users? Email = {email} car c'est un moyen de filtrer la collection d'utilisateurs, pas d'identifier une ressource spécifique par sa ressource identifiant / users / {id} est.
Kevin M
Très bonne réponse! Bravo pour ça. La seule chose que je recommanderais de faire est également de changer un peu votre API car REST doit être centré sur le nom, donc vos mappages de ressources devraient être quelque chose comme: GET /user/1234et nonGET /users/123
Sammy
36

En regardant cela de manière pragmatique, vous avez une collection d'utilisateurs:

/users   # this returns many

Chaque utilisateur dispose d'un emplacement de ressource dédié:

/users/{id}    # this returns one

Vous disposez également de plusieurs méthodes pour rechercher des utilisateurs:

/users?email={email}
/users?name=*bob*

Comme ce sont tous des paramètres de requête pour / users, ils devraient tous renvoyer des listes .. même s'il s'agit d'une liste de 1.

J'ai écrit un article de blog sur la conception pragmatique d'API RESTful ici qui en parle, entre autres, ici: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

Vinay Sahni
la source
Merci pour la réponse vinay. Mais si nous pensons à cela dans une autre perspective, {email} tout comme {id} va TOUJOURS renvoyer un résultat. Si nous recherchons vraiment, pourquoi ne pas utiliser? Id = {id} aussi bien que pour les e-mails? Je me demandais s'il y avait de toute façon d'être cohérent. PS: nouveau sur stackoverflow, je ne savais pas que je ne peux qu'une seule réponse. Mais merci pour votre réponse! Appréciez-le. Peut-être que vous pouvez également m'aider avec celui-ci: stackoverflow.com/questions/20508008/…
shahshi15
7
C'est là qu'entre en jeu l'aspect «conception» de la conception d'API. Votre ressource doit avoir un emplacement dédié. Où est l'emplacement? L'emplacement est-il par identifiant? Si tel est le cas, vous ne «cherchez» pas par identifiant, vous «obtenez» par identifiant. Mais vous recherchez par tout le reste. Bien sûr, il n'y a pas de règle fixe ici. C'est juste une perspective :)
Vinay Sahni
6
Je dirais également que de cette façon, votre API est plus stable. Vous savez vraiment que votre identifiant est unique, mais êtes-vous vraiment sûr de l'adresse e-mail? Même s'il est unique, il n'est probablement pas permanent puisque l'utilisateur peut le modifier. Donc / users? Email = {email} indique clairement qu'il s'agit bien d'une requête et non d'un accès à une ressource avec un identifiant permanent.
lex82
Je pense que c'est en fait la réponse la plus correcte. Le filtrage d'une collection par adresse e-mail peut être basé sur des caractères génériques afin de ne pas toujours renvoyer un seul résultat.
Kevin M
@VinaySahni Que diriez-vous d'un modèle comme: /user?by=email&email="[email protected] "/ user? By = id & id =" xashkhx "/ users? FilterA =" a "& filterB =" b "(pluriel pour plusieurs utilisateurs)
Shasak
2

À propos des ressources utilisateur

sur le chemin, /usersvous obtiendrez toujours une collection de ressources utilisateur renvoyées.

sur le chemin, /users/[user_id]vous pouvez vous attendre à ce que plusieurs choses se produisent:

  1. vous devriez obtenir une ressource singleton représentant la ressource utilisateur avec son identifiant [user_id] ou
  2. une réponse 404 introuvable si aucun utilisateur avec l'ID [user_id] n'existe ou
  3. un 401 interdit si vous n'êtes pas autorisé à accéder à la ressource utilisateur demandée.

Chaque singleton est identifié de manière unique par son chemin et son identifiant et vous les utilisez pour trouver la ressource. Il n'est pas possible d'utiliser plusieurs chemins pour le singleton.

Vous pouvez interroger le chemin /usersavec des paramètres de requête ( GETparamètres). Cela renverra une collection avec des utilisateurs qui répondent aux critères demandés. La collection renvoyée doit contenir les ressources utilisateur, toutes avec leur chemin d'accès aux ressources d'identification dans la réponse.

Les paramètres peuvent être n'importe quel champ présent dans les ressources de la collection; firstName, lastName,id

À propos de l'e-mail

L'e-mail peut être une ressource ou une propriété / champ de la ressource utilisateur.

- Email en tant que propriété de l'utilisateur:

Si le champ est une propriété de l'utilisateur, la réponse de l'utilisateur ressemblerait à ceci:

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: '[email protected]'
  ...
}

Cela signifie qu'il n'y a pas de critère spécial pour des e - mails, mais vous pouvez maintenant trouver un utilisateur par son email en envoyant la demande suivante: /[email protected]. Qui (en supposant que les e-mails sont uniques aux utilisateurs) renverrait une collection avec un élément utilisateur qui correspond à l'e-mail.

- Courriel en tant que ressource:

Mais si les e-mails des utilisateurs sont aussi des ressources. Ensuite, vous pouvez créer une API où /users/[user_id]/emailsrenvoie une collection d'adresses e-mail pour l'utilisateur avec un identifiant user_id. /users/[user_id]/emails/[email_id]renvoie l'email de l'utilisateur avec user_id et ['email_id']. Ce que vous utilisez comme identifiant dépend de vous, mais je m'en tiendrai à un entier. Vous pouvez supprimer un e-mail de l'utilisateur en envoyant une DELETEdemande au chemin qui identifie l'e-mail que vous souhaitez supprimer. Ainsi, par exemple, DELETEon /users/[user_id]/emails/[email_id]supprimera l'e-mail avec email_id qui appartient à l'utilisateur avec user_id. Très probablement, seul cet utilisateur est autorisé à effectuer cette opération de suppression. Les autres utilisateurs recevront une réponse 401.

Si un utilisateur ne peut avoir qu'une seule adresse e-mail, vous pouvez vous en tenir à /users/[user_id]/email Cela renvoie une ressource singleton. L'utilisateur peut mettre à jour son adresse e-mail en PUTtapant l'adresse e-mail à cette URL.

Se flétrir
la source