Une API REST peut avoir des paramètres d'au moins deux manières:
/api/resource/parametervalue
)/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?
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.
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.
Examinons maintenant les différents endroits où ces paramètres pourraient aller.
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!
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:
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.
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.
"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).
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 ...
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.
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.
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 PUT
ing 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.
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
Où
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".
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.
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.
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:
Mais si vous utilisez des variables de chemin, tous ces services peuvent mettre en cache vos demandes GET.
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:
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.