web-dev-qa-db-fra.com

Concevoir une API de requête RESTful avec une longue liste de paramètres de requête

Je dois concevoir une API de requête RESTful, qui renvoie un ensemble d'objets basé sur quelques filtres. La méthode HTTP habituelle pour cela est GET. Le seul problème est qu’il peut avoir au moins une douzaine de filtres, et si nous les transmettons tous en tant que paramètres de requête, l’URL peut devenir assez longue (assez longue pour être bloquée par un pare-feu).

Réduire le nombre de paramètres n'est pas une option.

Une alternative à laquelle je pourrais penser est d’utiliser la méthode POST sur l’URI et d’envoyer les filtres dans le cadre du corps POST. RESTfull (appel POST pour interroger des données).

Quelqu'un a de meilleures suggestions de design?

129
missionE46

N'oubliez pas qu'avec une API REST), tout dépend de votre point de vue.

Les deux concepts clés de l'API REST sont les points d'extrémité et les ressources (entités). Autrement dit, un point d'extrémité renvoie des ressources via GET ou accepte des ressources via POST = et PUT et ainsi de suite (ou une combinaison de ce qui précède).

Il est admis qu'avec POST, les données que vous envoyez peuvent entraîner ou non la création d'une nouvelle ressource et de son (des) terminal (s) associé (s), qui ne "vivront" probablement pas sous l'URL POST. En d’autres termes, lorsque vous POST vous envoyez des données quelque part à des fins de traitement. POST le point de terminaison n’est pas le lieu où la ressource pourrait normalement être trouvée.

Citant de RFC 2616 (avec les parties non pertinentes omises et les parties pertinentes mises en évidence):

9.5 POST

La méthode POST est utilisée pour demander au serveur d'origine d'accepter l'entité incluse dans la demande en tant que nouveau subordonné de la ressource identifiée par l'URI de demande dans la ligne de demande. POST est conçu pour permettre à une méthode uniforme de couvrir les fonctions suivantes:

  • ...
  • Fournir un bloc de données, tel que le résultat de la soumission d'un formulaire, à un processus de traitement de données;
  • ...

...

L'action effectuée par la méthode POST peut ne pas générer de ressource identifiable par un URI . Dans cette Dans ce cas, 200 (OK) ou 204 (aucun contenu) correspond au statut de réponse approprié, selon si la réponse comprend ou non une entité décrivant le résultat .

Si une ressource a été créée sur le serveur d'origine, la réponse DEVRAIT être 201 (Créé) ...

Nous nous sommes habitués aux terminaux et aux ressources représentant des "éléments" ou des "données", qu’il s’agisse d’un utilisateur, d’un message, d’un livre - quel que soit le domaine dans lequel le problème est dicté. Cependant, un noeud final peut également exposer une ressource différente, par exemple les résultats de recherche.

Prenons l'exemple suivant:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

C’est un exemple typique REST CRUD. Cependant, qu’en est-il si nous ajoutions:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

Il n'y a rien de non-RESTful à propos de ce noeud final. Il accepte les données (entité) sous la forme du corps de la demande. Ces données sont les critères de recherche - un DTO comme un autre. Ce noeud final produit une ressource (entité) en réponse à la requête: Résultats de la recherche . La ressource de résultats de recherche est une ressource temporaire, servie immédiatement au client, sans redirection, et sans être exposée à partir d'une autre URL canonique.

C'est toujours REST, sauf que les entités ne sont pas des livres - l'entité de demande est un critère de recherche de livre et l'entité de réponse est un résultat de recherche de livre.

110
Amir Abiri

Beaucoup de gens ont accepté la pratique selon laquelle un GET avec une chaîne de requête trop longue ou trop complexe (par exemple, les chaînes de requête ne gèrent pas facilement les données imbriquées) peut être envoyé sous la forme POST à la place, avec les données complexes/longues représentées dans le corps de la demande.

Recherchez la spécification pour POST dans la spécification HTTP. C'est incroyablement large. (Si vous voulez naviguer dans un cuirassé à travers une faille dans REST ... utilisez POST.)

Vous perdez certains des avantages de la sémantique de GET ... comme les tentatives automatiques car GET est idempotent, mais si vous pouvez vivre avec cela, il pourrait être plus facile d’accepter simplement de traiter des requêtes très longues ou compliquées avec POST.

(lol longue digression ... J'ai récemment découvert que, selon la spécification HTTP, GET peut contient un corps de document. Il y a une section qui dit, paraphrasant: "Toute demande peut avoir un corps de document sauf ceux énumérés. dans cette section "... et la section à laquelle elle fait référence n'en énumère aucune. J'ai cherché et trouvé un fil de discussion où les auteurs HTTP en parlaient, et c'était intentionnel, afin que les routeurs et autres ne soient pas obligés de se différencier Cependant, dans la pratique, de nombreux éléments d’infrastructure lâchent le corps d’un GET. Vous pouvez donc obtenir GET avec des filtres représentés dans le corps, comme POST, mais vous lanceriez les dés.)

72
Rob

En un mot: Créez un en-tête POST mais remplacez la méthode HTTP à l'aide de ) par X-HTTP-Method-Override .

Demande réelle

POSTE/livres

Corps de l'entité

{"titre": "Ipsum", "année": 2017}

en-têtes

X-HTTP-Method-Override: GET

Sur le serveur, vérifiez si l'en-tête X-HTTP-Method-Override existe, puis prenez sa valeur en tant que méthode permettant de construire la route vers le point de terminaison final dans le backend. Prenez également le corps de l'entité comme chaîne de requête. Du point de vue de l’arrière-plan, la demande est devenue un simple GET.

De cette façon, vous maintenez la conception en harmonie avec les principes de REST.

Edit: Je sais que cette solution était à l’origine destinée à résoudre le problème du verbe PATCH dans certains navigateurs et serveurs, mais elle fonctionne également pour moi avec le verbe GET dans le cas d’une très longue URL qui est le problème décrit dans le document. question.

6
Delmo