Lors de la conception d'une interface RESTful, la sémantique des types de demandes est considérée comme essentielle à la conception.
- GET - Lister une collection ou récupérer un élément
- PUT - Remplace la collection ou l'élément
- POST - Créer une collection ou un élément
- DELETE - Eh bien, erm, delete collection ou element
Cependant, cela ne semble pas couvrir le concept de "recherche".
Par exemple, lors de la conception d'une suite de services Web prenant en charge un site de recherche d'emploi, les conditions suivantes peuvent être remplies:
- Obtenir une offre d'emploi individuelle
- Se rendre à
domain/Job/{id}/
- Se rendre à
- Créer une offre d'emploi
- POST à
domain/Job/
- POST à
- Mettre à jour une offre d'emploi
- PUT à
domain/Job/
- PUT à
- Supprimer une offre d'emploi
- SUPPRIMER à
domain/Job/
- SUPPRIMER à
"Get All Jobs" est aussi simple:
- Se rendre à
domain/Jobs/
Cependant, comment la "recherche" d'emploi entre-t-elle dans cette structure?
Vous pouvez prétendre que c'est une variante de "list collection" et implémenter comme:
- Se rendre à
domain/Jobs/
Cependant, les recherches peuvent être complexes et il est tout à fait possible de générer une recherche générant une longue chaîne GET. En d’autres termes, si l’on fait référence à une question SO , il existe des problèmes liés à l’utilisation de chaînes GET plus longues que 2 000 caractères environ.
Un exemple pourrait être dans une recherche à facettes - en continuant l’exemple "job".
Je peux autoriser la recherche sur des facettes - "Technologie", "Titre du travail", "Discipline" ainsi que sur les mots-clés en texte libre, l'âge du travail, l'emplacement et le salaire.
Avec une interface utilisateur fluide et un grand nombre de technologies et de titres d'emploi, il est possible qu'une recherche englobe un grand nombre de choix de facettes.
Ajustez cet exemple en CV, plutôt qu'en emplois, apportez encore plus de facettes, et vous pouvez très facilement imaginer une recherche avec une centaine de facettes sélectionnées, ou même seulement 40 facettes de 50 caractères chacune (par exemple, Titres de poste, Noms d'université, Noms d’employeurs).
Dans cette situation, il peut être souhaitable de déplacer un PUT ou un POST afin de s’assurer que les données de recherche seront correctement envoyées. Par exemple:
- POST à
domain/Jobs/
Mais sémantiquement, c'est une instruction pour créer une collection.
Vous pouvez également dire que vous exprimerez ceci sous la forme d'une recherche:
- POST à
domain/Jobs/Search/
ou (comme suggéré par burninggramma ci-dessous)
- POST à
domain/JobSearch/
Sémantiquement, cela peut sembler logique, mais vous ne créez rien, vous faites une demande de données.
Donc, sémantiquement, c'est un GET , mais GET n'est pas garanti pour prendre en charge ce dont vous avez besoin.
La question est donc la suivante: essayer de rester aussi fidèle que possible à la conception RESTful tout en veillant à rester dans les limites du protocole HTTP, quelle est la conception la plus appropriée pour une recherche?
la source
domain/Jobs?keyword={keyword}
. Cela fonctionne très bien pour moi :) J'espère que leSEARCH
verbe deviendra un standard. programmers.stackexchange.com/questions/233158/…Réponses:
N'oubliez pas que les demandes GET présentent des avantages supérieurs à ceux des autres solutions:
1) Les requêtes GET peuvent être copiées à partir de la barre d’URL, elles sont digérées par les moteurs de recherche, elles sont "conviviales". Où "amical" signifie que normalement une requête GET ne doit rien modifier à l'intérieur de votre application (idempotent) . C'est le cas standard pour une recherche.
2) Tous ces concepts sont très importants, non seulement du point de vue de l'utilisateur et du moteur de recherche, mais aussi du point de vue architectural, de la conception d'API .
3) Si vous créez une solution de contournement avec POST / PUT, vous aurez des problèmes auxquels vous ne pensez pas pour le moment. Par exemple, dans le cas d'un navigateur, le bouton de navigation précédente / actualiser la page / l'historique. Celles-ci peuvent être résolues bien sûr, mais cela va être une autre solution de contournement, puis une autre et une autre ...
Compte tenu de tout cela, mon conseil serait:
a) Vous devriez pouvoir vous adapter à votre GET en utilisant une structure de paramètres intelligente . Dans les cas extrêmes, vous pouvez même opter pour des tactiques telles que cette recherche google dans laquelle je règle beaucoup de paramètres, mais c’est toujours une URL très courte.
b) Créez une autre entité dans votre application, telle que JobSearch . En supposant que vous ayez tellement d'options, il est probable que vous ayez également besoin de stocker ces recherches et de les gérer. Il vous suffit donc de clarifier votre application. Vous pouvez utiliser les objets JobSearch comme une entité complète, ce qui signifie que vous pouvez le tester / l’utiliser plus facilement .
Personnellement, j'essayerais de me battre avec toutes mes griffes pour le faire avec a) et lorsque tout espoir serait perdu, je ramperais avec les larmes aux yeux vers l'option b) .
la source
domain/Jobs/Search/
, peut - être avec ladomain/JobsSearch/
place, ou avez - vous dire quelque chose de différent? Pouvez-vous clarifier?TL; DR: GET pour le filtrage, POST pour la recherche
Je fais une distinction entre filtrer les résultats de la liste d'une collection par rapport à une recherche complexe. Le test décisif que j'utilise est essentiellement si j'ai besoin de plus que du filtrage (positif, négatif ou plage). Je considère qu'il s'agit d'une recherche plus complexe nécessitant un test POST.
Cela tend à être renforcé lorsque l’on réfléchit à ce qui sera retourné. J'utilise généralement uniquement GET si une ressource a un cycle de vie essentiellement complet (PUT, DELETE, GET, collection GET) . Généralement, dans une collection GET, je retourne une liste d'URI qui sont les ressources REST qui composent cette collection. Dans une requête complexe, il est possible que je tire plusieurs ressources afin de construire la réponse (pensez à une jointure SQL) afin que je ne renvoie pas d'URI, mais des données réelles. Le problème est que les données ne seront pas représentées dans une ressource, je devrai donc toujours renvoyer des données. Cela me semble être un cas clair d’exiger un POST.
-
Cela faisait longtemps et mon message original était un peu bâclé, alors j'ai pensé mettre à jour.
GET est le choix intuitif pour renvoyer la plupart des types de données, des collections de ressources REST, des données structurées d'une ressource, même des charges utiles uniques (images, documents, etc.).
POST est la méthode la plus répandue pour tout ce qui ne semble pas correspondre à GET, PUT, DELETE, etc.
À ce stade, je pense que les recherches simples et le filtrage ont un sens intuitif grâce à GET. Les recherches complexes dépendent de vos préférences personnelles, en particulier si vous ajoutez des fonctions d’agrégation, des corrélations croisées (jointures), des reformatages, etc. ) peut souvent avoir plus de sens en tant que corps de requête POST.
Je considère également l'aspect expérience de l'utilisation de l'API. Je souhaite généralement que la plupart des méthodes soient aussi simples à utiliser et intuitives que possible. J'appliquerai les appels plus flexibles (et donc plus complexes) dans des POST et vers un autre URI de ressource, en particulier s'il est incompatible avec le comportement d'autres ressources REST de la même API.
Dans les deux cas, la cohérence est probablement plus importante que la recherche dans GET ou POST.
J'espère que cela t'aides.
la source
GET /class?queryParams
. Du point de vue d'un utilisateur, la "classe" a toujours été une chose et vous n'avez pas à faire de jointures SQL bizarres.Dans REST, la définition des ressources est très large. Cependant, vous souhaitez vraiment regrouper certaines données.
Par exemple, l'URI principal de Google pointe vers une ressource de collection composée de "liens vers tous les sites Internet". Les paramètres de requête limitent cela aux sites que vous voulez voir.
(URI = identifiant de ressource universel, dont URL = localisateur de ressources universel, où le "http: //" bien connu est le format par défaut d'un URI. Donc, URL est un localisateur, mais dans REST, il est bon de généraliser à un identificateur de ressource. Les gens les utilisent de manière interchangeable, cependant.)
Et utilisez ensuite POST, qui est le verbe append ou process pour ajouter de nouveaux éléments à cette collection:
Notez que c'est la même structure pour l'
job
objet dans chaque cas. Un client peut obtenir une collection de travaux en utilisant des paramètres de requête pour affiner la recherche, puis utiliser le même format pour l'un des éléments afin de publier un nouveau travail. Ou il peut prendre l'un de ces éléments et PUT à son adresse URI pour mettre à jour celui-ci.Pour les chaînes de requête très longues ou compliquées, la convention permet d’envoyer celles-ci sous forme de requêtes POST. Regroupez les paramètres de la requête sous forme de paires nom / valeur ou d'objets imbriqués dans une structure JSON ou XML et envoyez-les dans le corps de la requête. Par exemple, si votre requête contient des données imbriquées au lieu de plusieurs paires nom / valeur. La spécification HTTP pour POST le décrit comme le verbe append ou process. (Si vous voulez naviguer dans un cuirassé à travers une échappatoire dans REST, utilisez POST.)
J'utiliserais cela comme plan de secours, cependant.
Ce que vous perdez quand vous faites cela, c’est que a) GET est nullipotent - c’est-à-dire que cela ne change rien - POST ne l’est pas. Donc, si l'appel échoue, le middleware ne réessayera pas automatiquement ni ne mettra en cache les résultats. 2) avec les paramètres de recherche dans le corps, vous ne pourrez plus couper et coller l'URI. En d'autres termes, l'URI n'est pas un identifiant spécifique pour la recherche que vous souhaitez.
Faire la distinction entre "créer" et "rechercher". Quelques options sont compatibles avec la pratique REST:
Vous pouvez le faire dans l'URI en ajoutant quelque chose au nom de la collection, par exemple recherche d'emploi au lieu d'emplois. Cela signifie simplement que vous traitez la collection de recherche comme une ressource distincte.
La sémantique de POST étant à la fois un processus append OR, vous pouvez identifier les corps de recherche avec la charge utile. Comme {job: ...} vs {search: ...}. C'est à la logique du POST de le poster ou de le traiter correctement.
C'est à peu près une préférence de conception / mise en œuvre. Je ne pense pas qu'il y ait une convention claire.
Donc, comme vous l’avez déjà expliqué, l’idée est de définir une ressource de collection pour
jobs
Effectuez une recherche avec les paramètres de requête GET + pour affiner la recherche. Les requêtes de données longues ou structurées vont dans le corps d'un POST (éventuellement dans une collection de recherche séparée). Créez avec POST pour ajouter à la collection. Et mettre à jour avec PUT vers un URI spécifique.
(FWIW, la convention de style avec les URI consiste à utiliser tous les caractères minuscules avec des mots séparés par des traits d'union. Mais cela ne signifie pas que vous devez le faire de cette façon.)
(En outre, je dois dire que, d'après votre question, il est clair que vous êtes sur une longue route. J'ai expliqué les choses de manière explicite simplement pour les aligner, mais votre question avait déjà abordé la plupart des problèmes sémantiques dans ce Je répondais juste avec une convention et une pratique)
la source
route
ne peuvent pas vraiment gérer le choix du traitement. Je devrais jeter un oeil à ça ...J'utilise généralement les requêtes OData, elles fonctionnent en tant qu'appel GET mais vous permettent de restreindre les propriétés renvoyées et de les filtrer.
Vous utilisez des jetons tels que
$select=
et$filter=
vous obtiendrez ainsi un URI ressemblant à ceci:Vous pouvez également faire en utilisant la pagination
$skip
et$top
et la commande.Pour plus d'informations, consultez OData.org . Vous n'avez pas spécifié la langue que vous utilisez, mais s'il s'agit d'ASP.NET, la plate-forme WebApi prend en charge les requêtes OData. Pour d'autres (PHP, etc.), il existe probablement des bibliothèques que vous pouvez utiliser pour les traduire en requêtes de base de données.
la source
JobsNearMeAddedInTheLast7Days
ou quoi que ce soit pour encapsuler la requête trop longue / complexe pour OData et l'exposer ensuite uniquement via des appels GET. .Une approche à considérer consiste à traiter l'ensemble des requêtes possibles comme une ressource de collection, par exemple
/jobs/filters
.POST
demandes à cette ressource, avec les paramètres de la requête dans le corps, va créer une nouvelle ressource soit ou d' identifier un filtre équivalent existant et renvoyer une URL contenant son ID:/jobs/filters/12345
.L'identifiant peut être utilisé dans une requête GET pour l' emploi:
/jobs?filter=12345
. LesGET
requêtes suivantes sur la ressource de filtre renverront la définition du filtre.Cette approche présente l'avantage de vous libérer du format de paramètre de requête pour la définition de filtre, ce qui vous donne potentiellement plus de pouvoir pour définir des filtres complexes. Les conditions OU sont un exemple auquel je peux penser qui sont difficiles à accomplir avec des chaînes de requête.
L'inconvénient de cette approche est que vous perdez la lisibilité de l'URL (bien que cela puisse être atténué en récupérant la définition via une
GET
requête pour la ressource de filtre). Pour cette raison, vous pouvez également vouloir prendre en charge le même ou un sous-ensemble des paramètres de requête sur la/jobs
ressource, comme vous le feriez pour une ressource de filtre. Cela pourrait être utilisé pour des requêtes plus courtes. Si cette fonctionnalité est fournie, afin de maintenir la capacité de mise en cache entre les deux types de filtrage, lors de l'utilisation de paramètres de requête sur la/jobs
ressource, l'implémentation doit créer / réutiliser en interne une ressource de filtrage et renvoyer un302
ou303
statut indiquant l'URL sous la forme/jobs?filter=12345
.la source
GET /jobs/37
et recevoir un résultat, puis quelqu'un supprime la ressource et 2 secondes plus tard, la même demande renvoie un 404. De même, siPOST /searches
vous êtes redirigé vers un résultat de recherche (la recherche est créée et vous recevez un 201 avec En-tête d’emplacement de la ressource), 2 secondes plus tard, le résultat peut être effacé de la mémoire et doit être régénéré. Pas besoin de stockage à long terme.C'est une vieille réponse mais je peux toujours contribuer un peu à la discussion. J'ai souvent observé un malentendu entre REST, RESTful et Architecture. RESTful ne mentionne jamais rien de la construction NON recherchée, il n’ya rien dans l’architecture RESTful, c’est un ensemble de principes ou de critères de conception.
Pour mieux décrire une recherche, nous devons parler d'une architecture en particulier et celle qui convient le mieux est l'architecture orientée ressources (ROA).
Dans RESTful, il y a des principes à concevoir, idempotent ne veut pas dire que le résultat ne peut pas changer, comme je l'ai lu dans certaines réponses, cela signifie que le résultat d'une requête indépendante ne dépend pas du nombre d'exécutions exécutées. Cela peut changer, imaginons que je mette à jour continuellement une base de données en lui fournissant des données servies par une API RESTful. L'exécution du même GET peut changer le résultat, mais cela ne dépend pas du nombre de fois qu'elle a été exécutée. Si je suis capable de geler le monde, cela signifie qu'il n'y a pas d'état, de transformation, quoi que ce soit à l'intérieur du service lorsque je demande la ressource qui conduit à un résultat différent.
Dans une architecture orientée ressources (appelons maintenant ROA par souci de brièveté), nous nous concentrons sur la ressource qui pourrait prendre beaucoup de choses:
Ce qui le rend unique en termes de ressources, c'est son adresse, ce qui signifie qu'il n'a qu'un seul URI.
De cette manière, la recherche s’intègre parfaitement dans RESTful en considérant le ROA . Nous devons utiliser GET car je suppose que votre recherche est une recherche normale et qu'elle ne change rien. Elle est donc idempotente (même si elle renvoie des éléments différents en fonction des nouveaux éléments ajoutés). Cela crée une certaine confusion parce que je pourrais m'en tenir à RESTful et non à ROA, cela signifie que je pourrais suivre un modèle qui crée une recherche et renvoie différentes choses avec les mêmes paramètres, car je n'utilise pas le principe d'adressabilité de ROA. Comment c'est? Eh bien, si vous envoyez les filtres de recherche dans le corps ou dans l'en-tête, la ressource n'est pas ADDRESSABLE.
Vous pouvez trouver les principes de quoi exactement et d'URI dans le document original de W3:
https://www.w3.org/DesignIssues/Axioms
Toute URL dans cette architecture doit être auto-descriptive. Il est nécessaire si vous suivez les principes pour tout traiter dans l'URI, cela signifie que vous pouvez utiliser / (barre oblique) pour séparer tout ce dont vous avez besoin ou paramètres de requête. Nous savons qu'il y a des limites à cela, mais c'est le modèle d'architecture.
En suivant le modèle de ROA dans REST, une recherche n’est pas plus que toute autre ressource. La seule différence est que les ressources proviennent d’un calcul et non d’une relation directe avec l’objet lui-même. Sur la base du principe, je pouvais aborder et obtenir un service de calcul arithmétique simple basé sur le schéma suivant:
http://myapi.com/sum/1/2
Où somme, 1 et 2 peuvent être modifiés mais le résultat du calcul est unique et adressable, chaque fois que j'appelle avec les mêmes paramètres j'obtiens le même et rien ne change dans le service. Les ressources / somme / 1/2 et / soustraire / 5/4 respectent parfaitement les principes.
la source
GET est ok, si vous avez une collection statique qui retourne toujours les mêmes résultats (représentation) pour un seul URI. Cela implique également que les données générant ces représentations ne sont jamais altérées. La source est une base de données en lecture seule.
Le fait que GET renvoie des résultats différents pour un même URI enfreint l' idempotence / la sécurité et le principe CoolURI et n'est par conséquent pas réactif . Il est possible que des verbes idempotents écrivent dans une base de données, mais ils ne doivent jamais affecter la représentation.
Une recherche commune commence par une requête POST qui renvoie une référence au résultat. Il génère le résultat (il est nouveau et peut être récupéré avec un GET ultérieur). Ce résultat peut être hiérarchique (références ultérieures avec des URI que vous pouvez obtenir), bien sûr, et peut réutiliser des éléments de recherches précédentes, si cela a du sens pour l'application.
En passant, je sais que les gens le font différemment. Vous n'avez pas besoin de m'expliquer à quel point il peut être pratique de violer REST.
la source