web-dev-qa-db-fra.com

REST API Meilleures pratiques: où placer les paramètres?

Une API REST peut avoir des paramètres d'au moins deux manières:

  1. faisant partie du chemin de l'URL (i.e. /api/resource/parametervalue)
  2. En tant qu'argument de requête (c'est-à-dire /api/resource?parameter=value)

Quelle est la meilleure pratique ici? Existe-t-il des directives générales pour utiliser 1 et quand utiliser 2?

Exemple concret: Twitter utilise des paramètres de requête pour spécifier des intervalles. (http://api.Twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321)

Serait-il considéré comme une meilleure conception de mettre ces paramètres dans le chemin d’URL?

348
Kalle Gustafsson

S'il existe des meilleures pratiques documentées, je ne les ai pas encore trouvées. Cependant, voici quelques directives que j'utilise pour déterminer où placer les paramètres dans une URL:

Les paramètres facultatifs ont tendance à être plus faciles à insérer dans la chaîne de requête.

Si vous souhaitez renvoyer une erreur 404 lorsque la valeur du paramètre ne correspond pas à une ressource existante, vous devez rechercher un paramètre de segment de chemin. par exemple. /customer/232 où 232 n'est pas un identifiant client valide.

Toutefois, si vous souhaitez renvoyer une liste vide, lorsque le paramètre n'est pas trouvé, nous vous suggérons d'utiliser des paramètres de chaîne de requête. par exemple. /contacts?name=dave

Si un paramètre affecte un sous-arbre entier de votre espace URI, utilisez un segment de chemin. par exemple. un paramètre de langage /en/document/foo.txt versus /document/foo.txt?language=en

Je préfère que les identificateurs uniques se trouvent dans un segment de chemin plutôt que dans un paramètre de requête.

Les règles officielles pour les URI se trouvent dans cette spécification RFC ici . Il existe également une autre spécification RFC très utile ici qui définit des règles pour paramétrer les URI.

254
Darrel Miller

Réponse tardive, mais j'ajouterai quelques informations supplémentaires à ce qui a été partagé, à savoir qu'il existe plusieurs types de "paramètres" dans une demande, et vous devriez en tenir compte.

  1. Localisateurs - E.g. identifiants de ressources tels que ID ou action/vue
  2. Filtres - par exemple des paramètres qui permettent de rechercher, de trier ou d’affiner l’ensemble des résultats.
  3. Etat - par exemple identification de session, clés d'api, whatevs.
  4. Contenu - par exemple données à stocker.

Examinons maintenant les différents endroits où ces paramètres pourraient aller.

  1. Demander des en-têtes et des cookies
  2. Chaîne de requête d'URL (vars "GET")
  3. Chemins d'URL
  4. Corps de la requête/multipart (vars "POST")

Généralement, vous souhaitez que l'état soit défini dans des en-têtes ou des cookies, selon le type d'informations d'état dont il s'agit. Je pense que nous pouvons tous être d'accord sur ce point. Utilisez des en-têtes HTTP personnalisés (X-My-Header) si vous en avez besoin.

De même, le contenu n'a qu'un seul emplacement auquel appartenir, qui se trouve dans le corps de la demande, sous forme de chaînes de requête ou de contenu http multipart et/ou JSON. Cela correspond à ce que vous recevez du serveur lorsqu'il vous envoie du contenu. Donc, vous ne devriez pas être impoli et faire les choses différemment.

Des localisateurs tels que "id = 5" ou "action = refresh" ou "page = 2" auraient du sens comme chemin d’URL, tels que mysite.com/article/5/page=2 où vous savez en partie ce que chaque partie est censée signifier (le des bases telles que article et 5 signifient évidemment que vous devez me procurer les données de type article avec id 5) et que des paramètres supplémentaires sont spécifiés dans le cadre de l'URI. Ils peuvent être sous la forme page=2 ou page/2 si vous savez qu'après un certain point dans l'URI, les "dossiers" sont des valeurs-clés appariées.

Les filtres vont toujours dans la chaîne de requête, car s'ils font partie de la recherche des bonnes données, ils ne sont là que pour renvoyer un sous-ensemble ou une modification de ce que les Locators retournent seuls. La recherche dans mysite.com/article/?query=Obama (sous-ensemble) est un filtre, tout comme /article/5?order=backwards (modification). Pensez à ce qu'il fait, pas simplement à son nom!

Si "view" détermine le format de sortie, il s’agit d’un filtre (mysite.com/article/5?view=pdf) car il renvoie une modification de la ressource trouvée au lieu de se connecter à la ressource souhaitée. Si au lieu de cela il décide quelle partie spécifique de l'article nous arrivons à voir (mysite.com/article/5/view=summary), alors c'est un localisateur.

Rappelez-vous, réduire n ensemble de ressources est en train de filtrer. Localiser quelque chose de spécifique dans une ressource, c'est localiser ... duh. Le filtrage de sous-ensembles peut renvoyer un nombre quelconque de résultats (même 0). La localisation trouvera toujours cette instance spécifique de quelque chose (si elle existe). Le filtrage des modifications renvoie les mêmes données que le localisateur, à l'exception de celles modifiées (si une telle modification est autorisée).

J'espère que cela a contribué à donner aux gens des moments d'eureka s'ils n'ont pas compris où mettre leurs affaires!

152
Tor Valamo

Cela dépend d'un design. Il n'y a pas de règles pour les URI à REST sur HTTP (leur principale caractéristique est qu'ils sont uniques). Souvent, il est question de goût et d'intuition ...

Je prends l'approche suivante:

  • url path-element: la ressource et son élément path constituent un parcours de répertoire et une sous-ressource (par exemple,/items/{id},/users/items). En cas de doute, demandez à vos collègues s'ils pensent que traverser et qu'ils pensent dans "un autre répertoire", l'élément de chemin le plus probable est le bon choix
  • paramètre url: quand il n'y a pas vraiment de traversée (les ressources de recherche avec plusieurs paramètres de requête en sont un très bel exemple)
21
manuel aldana

IMO les paramètres devraient être meilleurs comme arguments de requête. L'URL est utilisé pour identifier la ressource, tandis que les paramètres de requête ajoutés permettent de spécifier quelle partie de la ressource vous souhaitez, quel que soit l'état de la ressource, etc.

18
PeterWong

Conformément à la REST Implementation,

1) Les variables de chemin sont utilisées pour l'action directe sur les ressources, comme un contact ou une chanson, par exemple.
GET etc/api/resource/{songid} ou
GET etc/api/resource/{contactid} renverra les données respectives.

2) Les requêtes permanentes/l'argument sont utilisées pour les ressources indirectes telles que les métadonnées d'une chanson ex .., GET/api/resource/{songid}? Metadata = genres, les genres seront renvoyés cette chanson particulière.

17
Satish Bellapu

"Pack" et POST vos données par rapport au "contexte" fourni par univers-resource-locator, ce qui signifie n ° 1 pour l'intérêt du localisateur.

Attention aux limitations avec # 2. Je préfère les POST au # 1.

note: les limitations sont discutées pour

POST in Existe-t-il une taille maximale pour le contenu du paramètre POST?

GET in la longueur d'une requête GET est-elle limitée? et taille maximale des paramètres d'URL dans _GET

p.s. ces limites sont basées sur les capacités du client (navigateur) et du serveur (configuration).

16
dgm

Selon le norme URI , le chemin concerne les paramètres hiérarchiques et la requête concerne les paramètres non hiérarchiques. Ofc. ce qui est hiérarchique pour vous peut être très subjectif.

Dans les situations où plusieurs URI sont affectés à la même ressource, j'aime mettre les paramètres nécessaires à l'identification dans le chemin et les paramètres nécessaires à la création de la représentation dans la requête. (Pour moi, il est plus facile d’acheminer.)

Par exemple:

  • /users/123 et /users/123?fields="name, age"
  • /users et /users?name="John"&age=30

Pour réduire la carte, j'aime utiliser les approches suivantes:

  • /users?name="John"&age=30
  • /users/name:John/age:30

Donc, c'est vraiment à vous (et à votre routeur côté serveur) comment vous construisez vos URI.

Remarque: Il suffit de mentionner ces paramètres comme paramètres de requête. Vous définissez donc un langage de requête simple. Par des requêtes complexes (qui contiennent des opérateurs tels que et, ou, supérieur à, etc.), je vous suggère d'utiliser un langage de requête déjà existant. Les capacités de modèles d'URI sont très limitées ...

5
inf3rno

En tant que programmeur souvent sur le client, je préfère l’argument de requête. En outre, pour moi, il sépare le chemin de l'URL des paramètres, ajoute de la clarté et offre plus d'extensibilité. Cela me permet également d’avoir une logique séparée entre le bâtiment URL/URI et le constructeur de paramètres.

J'aime bien ce que Manuel Aldana a dit à propos de l'autre option s'il y a une sorte d'arbre impliqué. Je peux voir des parties spécifiques à l'utilisateur être traitées de cette manière.

4
Joe Plante

Voici mon avis.

Les paramètres de requête sont utilisés comme métadonnées pour une requête. Ils agissent en tant que filtre ou modificateur pour un appel de ressource existant.

Exemple:

/calendar/2014-08-08/events

devrait donner des événements de calendrier pour ce jour.

Si vous voulez des événements pour une catégorie spécifique

/calendar/2014-08-08/events?category=appointments

ou si vous avez besoin d'événements de plus de 30 minutes

/calendar/2014-08-08/events?duration=30

Un test décisif consisterait à vérifier si la demande peut toujours être servie sans paramètres de requête.

4
Jay

Il n'y a pas de règles strictes, mais la règle empirique d'un point de vue purement conceptuel que j'aime utiliser peut être résumée brièvement ainsi: un chemin d'URI (par définition) représente une ressource et les paramètres de requête sont essentiellement des modificateurs sur cette ressource. . Jusqu'à présent, cela n'aide probablement pas ... Avec une API REST, vous disposez des méthodes principales pour agir sur une ressource unique en utilisant GET, PUT et DELETE. Par conséquent, si quelque chose doit être représenté dans le chemin ou en tant que paramètre peut être réduit à savoir si ces méthodes ont un sens pour la représentation en question. Voulez-vous raisonnablement PUT quelque chose sur ce chemin et serait-il sémantiquement judicieux de le faire? Vous pouvez bien sûr PUT quelque chose à peu près n'importe où et plier le back-end pour le gérer, mais vous devriez être PUTing ce qui équivaut à une représentation de la ressource réelle et non à une version inutilement contextualisée de celle-ci. Pour les collections, la même chose peut être faite avec POST. Si vous souhaitez ajouter à une collection particulière ce que serait une URL ayant un sens pour POST to.

Cela laisse encore des zones grises car certains chemins pourraient indiquer le nombre d'enfants de ressources parents, ce qui est quelque peu discrétionnaire et dépend de leur utilisation. La ligne dure que cela trace est que tout type de représentation transitive doit être effectué à l'aide d'un paramètre de requête, car il ne disposerait pas d'une ressource sous-jacente.

En réponse à l'exemple du monde réel donné dans la question initiale (API de Twitter), les paramètres représentent une requête transitive qui filtre sur l'état des ressources (plutôt qu'une hiérarchie). Dans cet exemple particulier, il serait tout à fait déraisonnable d'ajouter à la collection représentée par ces contraintes, et cette requête ne pourrait pas non plus être représentée comme un chemin qui aurait un sens dans les termes d'un graphe d'objet.

L'adoption de ce type de perspective orientée ressources peut facilement mapper directement sur le graphe d'objet de votre modèle de domaine et conduire la logique de votre API au point que tout fonctionne très proprement et de manière assez autodocumentée une fois qu'il est devenu clair. Le concept peut également être clarifié en s’éloignant des systèmes qui utilisent le routage d’URL traditionnel mappé sur un modèle de données mal adapté (c’est-à-dire un SGBDR). Apache Sling serait certainement un bon point de départ. Le concept d'envoi d'un objet traversant dans un système tel que Zope fournit également un analogue plus clair.

4
Matt Whipple

Une "dimension" de ce sujet a été laissée de côté mais elle est très importante: il est parfois nécessaire que les "meilleures pratiques" soient en phase avec la plate-forme que nous mettons en œuvre ou augmentons avec les capacités REST.

Exemple pratique:

De nombreuses applications Web implémentent aujourd'hui l'architecture MVC (Model, View, Controller). Ils supposent qu'un certain chemin standard est fourni, encore plus lorsque ces applications Web sont dotées de l'option "Activer les URL de référencement".

Il suffit de mentionner une application Web assez célèbre: une boutique de commerce électronique OpenCart. Lorsque l'administrateur active les "URL de référencement", il s'attend à ce que ces URL soient dans un format MVC assez standard, tel que:

http://www.domain.tld/special-offers/list-all?limit=25

  • special-offers est le contrôleur MVC qui traitera l'URL (montrant la page des offres spéciales)

  • list-all est le nom de l'action ou de la fonction du contrôleur à appeler. (*)

  • la limite = 25 est une option, indiquant que 25 éléments seront affichés par page.

(*) list-all est un nom de fonction fictif que j'ai utilisé pour plus de clarté. En réalité, OpenCart et la plupart des frameworks MVC ont une fonction implicite (et généralement omise dans l'URL) index qui est appelée lorsque l'utilisateur souhaite qu'une action par défaut soit effectuée. Donc, l'URL du monde réel serait:

http://www.domain.tld/special-offers?limit=25

Avec une application ou une structure frameworkd maintenant assez standard, semblable à la précédente, vous obtiendrez souvent un serveur Web optimisé pour celui-ci, qui réécrit ses URL (le véritable "URL non référencée" serait: http://www.domain.tld/index.php?route=special-offers/list-all&limit=25) .

Par conséquent, en tant que développeur, vous devez faire face à l'infrastructure existante et adapter vos "meilleures pratiques". Sauf si vous êtes l'administrateur système, vous savez exactement comment ajuster une configuration de réécriture Apache/NGinx (cette dernière peut être désagréable!), Etc. sur.

Ainsi, votre API REST serait souvent bien plus conforme aux normes de l’application Web référente, à la fois par souci de cohérence et par facilité/rapidité (et donc par économie de budget).

Pour revenir à l'exemple pratique ci-dessus, une API cohérente REST serait quelque chose avec des URL telles que:

http://www.domain.tld/api/special-offers-list?from=15&limit=25

ou (URL non SEO)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

avec un mélange d'arguments "chemins formés" et d'arguments "requête formée".

2
Dario Fumagalli

Je suis généralement orienté vers # 2, en tant qu'argument de requête (c'est-à-dire/api/resource? Paramètre = valeur).

Une troisième option consiste à publier le paramètre = valeur dans le corps.

En effet, cela fonctionne mieux pour les ressources multi-paramètres et est plus extensible pour une utilisation future.

Peu importe celui que vous choisissez, assurez-vous de n'en choisir qu'un, ne vous mélangez pas. Cela conduit à une API déroutante.

2
NorthIsUp

Je vois beaucoup d'API REST qui ne gèrent pas bien les paramètres. Un exemple fréquent est celui où l'URI inclut des informations personnellement identifiables.

http://software.danielwatrous.com/design-principles-for-rest-apis/

Je pense qu'une question corollaire est quand un paramètre ne devrait pas être un paramètre du tout, mais devrait plutôt être déplacé vers le EN-TÊTE ou CORPS de la requête.

1
Daniel Watrous

C'est une question très intéressante.

Vous pouvez utiliser les deux, il n'y a pas de règle stricte à ce sujet, mais l'utilisation de variables de chemin d'URI présente certains avantages:

  • Cache: La plupart des services de cache Web sur Internet ne mettent pas en cache les demandes GET lorsqu'ils contiennent des paramètres de requête. Ils le font car de nombreux systèmes RPC utilisent des requêtes GET pour modifier les données sur le serveur (échouez! Get doit être une méthode sûre).

Mais si vous utilisez des variables de chemin, tous ces services peuvent mettre en cache vos demandes GET.

  • Hiérarchie: Les variables de chemin peuvent représenter la hiérarchie:/Ville/Rue/Lieu

Il donne à l'utilisateur plus d'informations sur la structure des données.

Mais si vos données n’ont aucune relation hiérarchique, vous pouvez toujours utiliser les variables Path, en utilisant une virgule ou un point-virgule:

/ Ville/longitude, latitude

En règle générale, utilisez des virgules lorsque l'ordre des paramètres est important, utilisez des points-virgules lorsque l'ordre n'a pas d'importance:

/ IconGenerator/rouge; bleu; vert

Outre ces raisons, il existe des cas où il est très courant d'utiliser des variables de chaîne de requête:

  • Lorsque vous avez besoin que le navigateur mette automatiquement des variables de formulaire HTML dans l'URI
  • Quand vous avez affaire à un algorithme. Par exemple, le moteur Google utilise des chaînes de requête:

http: // www.google.com/search?q=rest

Pour résumer, il n’ya aucune raison forte d’utiliser une de ces méthodes, mais chaque fois que vous le pouvez, utilisez des variables d’URI.

0
jfcorugedo