Quelle est la bonne façon de faire une méthode de recherche RESTful complexe?

44

En suivant les principes de REST, je souhaiterais créer une méthode GET pour mon API qui effectue une recherche à l'aide de certains critères et renvoie les résultats au client. Le problème est que les critères peuvent avoir jusqu'à 14 paramètres, l'un d'eux est une liste d'objets complexes, donc ...

  • Je ne sais même pas s'il est possible de coder / décoder ces objets complexes dans / à partir de paramètres d'URL.

  • Je n'ai pas calculé combien de temps l'URL pourrait avoir mais je suis sûr que ce sera assez grand et peut-être atteindre la limite de longueur d'URL?

En outre, la recherche devrait afficher les résultats en "temps réel", je veux dire, chaque fois que l'utilisateur modifie quelque chose à partir du formulaire de recherche, il devrait pouvoir voir les nouveaux résultats sans appuyer sur le bouton "Rechercher".

Pourriez-vous m'expliquer ces points et quel conseil donneriez-vous pour créer une méthode de recherche reposante avec beaucoup de paramètres?

Anat0lius
la source
3
En passant (je remarque qu'aucune des deux réponses au moment de la rédaction ne mentionne la partie temps réel), les recherches en temps réel devraient normalement consister simplement à envoyer la demande mise à jour à plusieurs reprises. Par exemple, lorsque vous tapez, vous seriez d' envoyer des demandes de choses comme search?q=t, search?q=te, search?q=testet ainsi de suite. Envisagez de limiter la fréquence d'envoi de la requête pour éviter de nuire à votre serveur. Vous pouvez également renvoyer beaucoup d’informations et filtrer du côté client. Cela fonctionne bien si l’utilisateur entre de grandes catégories qui permettent de réduire considérablement les choses.
Kat
2
Quelle que soit la solution, veillez à échanger des données dans un format neutre sur le plan technologique. Donc, n'utilisez pas de représentation interne ou il sera plus difficile d'écrire des clients pour votre API.
Kwebble
Selon vos besoins, cette bibliothèque pourrait faire le travail: github.com/jirutka/rsql-parser . Il a une extension JPA si vous utilisez JPA, ou vous pouvez écrire votre propre visiteur à mapper à l'API de votre moteur de recherche. Et vous pouvez ajouter votre propre opérateur.
Walfrat

Réponses:

54

Avant de lire ma réponse, je voudrais dire que je suis d’accord avec @Neil. Nous devons choisir nos batailles. Nous voulons généralement faire de notre mieux, mais il y a parfois trop peu de place pour la discussion et nous devons prendre des décisions contre notre volonté.

Quoi qu'il en soit, dans la réponse de Neil, il me manque une dernière chose. Documentation . Juste pour s'assurer que les développeurs savent que les requêtes POST /searchsont sécurisées.

Cela dit.

1. Donner une chance d'obtenir

Considérons l' GEToption en premier. Découvrez la longueur maximale de cette question dans l' URL . Déterminez si votre chaîne de requête la plus longue contient plus de 2 000 caractères. Si ce n'est pas le cas, et que vous ne vous attendez pas à cela, allez-y GET. Cela peut paraître moche, mais au moins vous pouvez marquer l’URL en signet et, bien sûr, elle présente tous les avantages dérivés de la sémantique de la méthode (idempotence, safe et mise en cache).

1.1 Essayez d'encoder la chaîne de requête

Par exemple, en base 64. Même javascript prend en charge les encodages en base 64 .

Voici comment cela fonctionne:

  1. Construisez le JSON avec tous les filtres et normalisez-le.
  2. Analyse le en chaîne
  3. L'encoder
  4. Envoyez le JSON codé en tant que request param ( /search?q=SGVsbG8gV29ybGQh....).
  5. Côté serveur, décodez le paramètre q .
  6. Désérialiser la chaîne JSON

Auparavant, créez la chaîne JSON la plus longue possible, encodez-la et prenez la longueur. Évaluez si la chaîne encodée tient dans l'URL. J'ai implémenté l'extrait suivant sur Fiddle.js pour que vous puissiez le tester. (J'espère que cela fonctionne toujours) 1

Les codages en base 64 sont déterministes et réversibles, il n’ya donc aucune chance de collision.

Avec les requêtes codées, nous pourrions également enregistrer des recherches dans la base de données, marquer l’URL du signet, partager des liens, etc. Et, bien sûr, nous n’avons pas à échapper / annuler la chaîne.

1.2 Essayez avec des alias

En lisant ce blog sur la conception des API REST, je me suis rappelé une alternative supplémentaire. Alias ​​pour les requêtes courantes .

Je trouve cela intéressant pour les prochaines raisons

  • Raccourcissez la longueur de la chaîne de requête. Cela rend l'API plus propre et conviviale

    GET / tickets /? Status = fermé & ferméAt = xxx vs GET / billets / récemment fermé /

  • Combinable avec plus d'alias ou plus de paramètres de demande.

    GET / tickets /? Status = fermé & ferméAt = xxx & dans = 30min vs GET / billets / récemment fermé /? Dans = 30min

  • Nous pouvons combiner des alias avec des chaînes de requête codées

    GET / tickets /? Status = fermé & ferméAt = xxx & dans = 30min vs GET / billets / récemment fermé /? Q = SGVsbG8g ...


1: J'ai utilisé JSON, mais nous pourrions utiliser d'autres formats dès que nous pourrons le désérialiser sur le serveur.

Laiv
la source
2
C'est à la fois pratique et correct. Il est également intéressant de noter que la plupart des langages de programmation rendent triviale la transformation d'un hachage en chaîne de requête. Il est donc très facile de commencer avec une action GET.
Aluan Haddad
1
J'adore Spring stackoverflow.com/questions/16942193/… Je n'arrive pas à croire que cela ait fonctionné au premier essai: D. La longueur de l’url est inférieure à 1k, bien que nous ayons encore besoin d’itérer les spécifications.
anat0lius
Ensuite, allez avec GET. Pour la simplicité. Avec Spring MVC, vous pouvez obtenir le même mappage avec GET. Recherchez WebArgumentResolver du printemps ;-)
Laiv
Base64 gonfle la taille de la charge utile d'environ 4/3. Bien que le codage en url puisse atteindre 3/1 pour les caractères spéciaux, les requêtes contenant principalement des caractères sécurisés conserveront la même taille. Y a-t-il une autre raison d'utiliser base64?
villasv
Pas vraiment. Je n'aime pas les URL (un) d'échappement. La surcharge de la charge utile est le compromis ici. Il doit toujours correspondre à la taille maximale de GET par demande. C'est pourquoi j'ai construit l'extrait de code. Pour l'utilisateur d'essayer. Lorsque j'ai écrit la réponse, j'ai priorisé la sémantique Web sur les détails de la mise en œuvre. Le but de la réponse est "continuez d'essayer avec GET". Trouvez votre chemin ou utilisez l'un de ceux-ci que je partage avec vous.
Laiv
13

Si tout ce que vous avez est un marteau, tout ressemble à un clou. Il semble que le problème ici est que vous essayez de transformer une page de recherche en une page RESTful, ce qui semble difficilement être un motif courant pour la conception RESTful.

Il suffit simplement d’obtenir une requête POST avec les paramètres fournis par l’utilisateur pour obtenir les informations dont vous avez besoin à partir du backend. Je suppose que vous n'avez pas besoin de faire autre chose que d'effectuer une recherche. Il est donc inutile d'insérer cette page dans cette page. Ajoutez simplement un / search à la fin de votre URL pour ne pas risquer de vous heurter à des conflits avec votre page / users qui seraient RESTful.

Neil
la source
2
@LiLou_: Pour cette exigence, il n'y a que deux possibilités réalistes: 1. Lisez toutes les données sur votre serveur et effectuez le filtrage à cet endroit. Cela peut être prohibitif dans la quantité de mémoire requise. 2. Faites une nouvelle demande au serveur pour chaque modification des critères de recherche. Peu importe qu'il s'agisse d'une requête POST ou d'une requête GET, mais la latence réseau impliquée peut perturber le sens des mises à jour "en temps réel" de l'utilisateur.
Bart van Ingen Schenau le
2
Je suis d'accord pour être en désaccord, POST signifie autre chose sémantiquement. Je suggèrerais d'aller avec le GET et de transmettre toutes les données de filtre dans le paramètre de requête maintenant s'il y a trop de paramètres, c'est une erreur au niveau de l'application.
CodeYogi
2
@CodeYogi Parfois, le client ne vous laisse pas un espace de discussion. J'ai implémenté des pages d'affichage de type Excel avec 40 à 50 colonnes, chacune avec son propre filtre. Et triable bien sûr. Quoi qu'il en soit, c'est toujours possible avec GET, mais cela ne semble pas trop à la mode
Laiv
1
@ Laiv dans ce cas, une discussion sérieuse est nécessaire car le POST est destiné au changement d'état du serveur. Les cas d'utilisation comme celui-ci ne sont pas exceptionnels et doivent donc être pris en charge sans piratage.
CodeYogi
2
Dans ces cas, la documentation est un must. J'ai eu une discussion sérieuse avec les clients concernant la convivialité de leurs applications. Plus tard, il a été prouvé que j'avais raison, car l'utilisateur final était d'accord avec moi. Cependant, vous devez parfois choisir vos batailles.
Laiv
0

Cela dépend entièrement de votre modèle d'API: en tant que rien ou en tant que verbe.

Si l'API est non, alors vous voudrez peut-être obtenir une liste d'objets comme suit:

GET: /api/v1/objects

Dans ce cas, vous devez envoyer les données en tant que paramètres de demande. Vous devez donc décrire vos paramètres sous forme de liste plate de valeurs-clés:

GET: /api/v1/objects

key1 : val1
key2.key1 : val 21
key2.key2 : val 22
....

Certaines plates-formes prennent en charge le résolveur de paramètres personnalisé (par exemple, Spring MVC), et vous pouvez convertir les paramètres en objet.

Mostafa
la source