Comment concevoir Reposante de recherche/filtrage?

je suis en train de concevoir et d'implémenter une API RESTful en PHP. Cependant, j'ai échoué dans la mise en œuvre de mon projet initial.

GET /users # list of users
GET /user/1 # get user with id 1
POST /user # create new user
PUT /user/1 # modify user with id 1
DELETE /user/1 # delete user with id 1

pour l'instant assez standard, non?

Mon problème est avec le premier GET /users . J'envisage l'envoi de paramètres dans le corps de la requête pour filtrer la liste. C'est parce que je veux être capable de spécifier des filtres complexes sans obtenir une url super longue, comme:

GET /users?parameter1=value1&parameter2=value2&parameter3=value3&parameter4=value4

à la place je voulais avoir quelque chose comme:

GET /users
# Request body:
{
    "parameter1": "value1",
    "parameter2": "value2",
    "parameter3": "value3",
    "parameter4": "value4"
}

qui est beaucoup plus lisible et vous donne de grandes possibilités de mettre des filtres complexes.

de toute façon, file_get_contents('php://input') n'a pas retourné le corps de la requête pour les requêtes GET . J'ai aussi essayé http_get_request_body() , mais l'hébergement partagé que j'utilise n'a pas pecl_http . Je ne suis pas sûr que ça aurait aidé de toute façon.

j'ai trouvé ce question et réalisé que GET n'est probablement pas censé avoir un corps de requête. C'était peu concluant, mais ils ont déconseillé.

donc maintenant je ne sais pas quoi faire. Comment concevez-vous une fonction RESTful search/filterng?

je suppose que je pourrais utiliser POST , mais cela ne semble pas très reposant.

332
demandé sur Community 2011-02-16 21:45:04
la source

7 ответов

la meilleure façon de mettre en œuvre une recherche reposante est de considérer la recherche elle-même comme une ressource. Ensuite, vous pouvez utiliser le verbe POST parce que vous créez une recherche. Vous ne devez pas littéralement créer quelque chose dans une base de données afin d'utiliser un POST.

par exemple:

Accept: application/json
Content-Type: application/json
POST http://example.com/people/searches
{
  "terms": {
    "ssn": "123456789"
  },
  "order": { ... },
  ...
}

vous créez une recherche du point de vue de l'utilisateur. Les détails de la mise en œuvre sont sans importance. Certains APIs reposants mai même pas besoin persistance. C'est un détail d'implémentation.

342
répondu Jason Harrelson 2014-03-20 09:11:48
la source

si vous utilisez le corps de la requête dans une requête GET, vous violez le principe REST, parce que votre requête GET ne pourra pas être mise en cache, parce que le système de cache n'utilise que l'URL.

et pire encore, votre URL ne peut pas être signetée, car L'URL ne contient pas toutes les informations nécessaires pour rediriger l'utilisateur vers cette page ""

utilisez les paramètres D'URL ou de requête au lieu des paramètres de corps de requête.

p.ex.:

/myapp?var1=xxxx&var2=xxxx
/myapp;var1=xxxx/resource;var2=xxxx 

en fait, le HTTP RFC 7231 dit que:

une charge utile contenue dans un message de requête GET n'a pas de sémantique définie; l'envoi d'un corps de charge utile sur une requête GET pourrait entraîner le rejet de la requête par certaines implémentations existantes.

pour plus d'informations, regardez ici

90
répondu jfcorugedo 2016-09-16 16:56:56
la source

il semble que le filtrage/la recherche de ressources puisse être mis en œuvre de manière reposante. L'idée est d'introduire un nouveau paramètre appelé /filters/ ou /api/filters/ .

utilisant ce paramètre filtre peut être considéré comme une ressource et donc créé via la méthode POST . Cette façon - bien sûr-corps peut être utilisé pour transporter tous les paramètres ainsi que des structures de recherche/filtre complexes peuvent être créés.

après création d'un tel filtre il y a deux possibilités pour obtenir le résultat de recherche/filtre.

  1. une nouvelle ressource avec un identifiant unique sera retournée avec le code de statut 201 Created . Ensuite, en utilisant cet ID une GET demande peut être faite à /api/users/ comme:

    GET /api/users/?filterId=1234-abcd
    
  2. après que le nouveau filtre est créé via POST il ne répondra pas avec 201 Created mais à la fois avec 303 SeeOther avec Location en-tête pointant vers /api/users/?filterId=1234-abcd . Cette redirection sera traitée automatiquement via la bibliothèque sous-jacente.

dans les deux scénarios, deux requêtes doivent être faites pour obtenir les résultats filtrés - ce qui peut être considéré comme un inconvénient, en particulier pour les applications mobiles. Pour les applications mobiles, j'utiliserais l'appel simple POST à /api/users/filter/ .

comment conserver les filtres créés?

ils peuvent être stockés en DB et utilisés plus tard. Ils peuvent également être stockés dans un stockage temporaire, par exemple redis, et avoir une certaine TTL après laquelle ils expireront et seront retirés.

Quels sont les avantages de cette idée?

filtres, les résultats filtrés sont cachables et peuvent même être signalisés.

36
répondu Opal 2017-11-14 17:41:51
la source

je pense que vous devriez aller avec les paramètres de requête mais seulement tant qu'il n'y a pas un en-tête HTTP approprié pour accomplir ce que vous voulez faire. La spécification HTTP ne dit pas explicitement que GET ne peut pas avoir de corps. Cependant ce papier déclare:

par convention, lorsque la méthode GET est utilisé, toutes les informations nécessaires pour identifier la ressource est encodée dans URI. Il n'y a pas de convention dans HTTP / 1.1 Pour une interaction sûre (e.g., récupération) où le client fournit données au serveur dans une entité HTTP corps plutôt que dans la partie requête de URI. Cela signifie que pour la sécurité opérations, URIs peut être long.

13
répondu Daff 2011-02-16 22:02:24
la source

ne vous inquiétez pas trop si votre API initiale est complètement RESTful ou pas (surtout si vous êtes juste aux stades alpha). Faites d'abord fonctionner la plomberie arrière. Vous pouvez toujours faire une sorte de transformation/réécriture D'URL pour cartographier les choses, en raffinant itérativement jusqu'à ce que vous obteniez quelque chose de suffisamment stable pour un test généralisé ("bêta").

vous pouvez définir URIs dont les paramètres sont encodés par position et convention sur L'URIs eux-mêmes, préfixés par un chemin que vous connaissez vous aurez toujours une correspondance. Je ne connais pas PHP, mais je suppose qu'une telle facilité existe (comme elle existe dans d'autres langues avec des cadres de web):

.ie. Faites une recherche de type" utilisateur " avec param[i]=valeur[i] pour i=1..4 sur le magasin #1 (avec valeur1,valeur2,valeur3,... comme un raccourci pour les paramètres de requête URI):

1) GET /store1/search/user/value1,value2,value3,value4

ou

2) GET /store1/search/user,value1,value2,value3,value4

ou comme suit (même si je ne le recommanderais pas, plus sur cela plus tard)

3) GET /search/store1,user,value1,value2,value3,value4

avec l'option 1, vous mappez tous les URIs préfixés par /store1/search/user vers le gestionnaire de recherche (ou quelque soit la désignation PHP) en défaut de faire des recherches pour les ressources sous store1 (équivalent à /search?location=store1&type=user .

par convention documentée et appliquée par L'API, les valeurs des paramètres 1 à 4 sont séparées par des virgules et présentées dans cet ordre.

L'Option 2 ajoute le type de recherche (dans ce cas user ) comme position le paramètre #1. L'une ou l'autre option n'est qu'un choix esthétique.

Option 3 est également possible, mais je ne pense pas que je voudrais. Je pense que la capacité de recherche à l'intérieur de certaines ressources devrait être présentée dans l'URI lui-même avant la recherche elle-même (comme si elle indiquait clairement dans l'URI que la recherche est spécifique à l'intérieur de la ressource).)

l'avantage de ceci par rapport aux paramètres de passage sur L'URI est que la recherche fait partie de L'URI (traitant ainsi une recherche en tant que ressource, une ressource dont le contenu peut - et va - changer avec le temps.) L'inconvénient est que l'ordre des paramètres est obligatoire.

une fois que vous avez fait quelque chose comme ça, vous pouvez utiliser GET, et ce serait une ressource en lecture seule (puisque vous ne pouvez pas L'afficher ou le mettre-il est mis à jour quand il est obtenu). Ce serait aussi une ressource qui n'existe que lorsqu'elle est invoquée.

on pourrait aussi y ajouter plus de sémantique en cachant les résultats pour une période de temps ou avec une suppression provoquant la suppression du cache. Cela, cependant, pourrait aller à l'encontre de ce que les gens utilisent généralement Supprimer pour (et parce que les gens contrôlent généralement la mise en cache avec des en-têtes de mise en cache.)

la façon dont vous vous y prenez serait une décision de conception, mais ce serait la façon dont je me comporterais. Ce n'est pas parfait, et je suis sûr qu'il y aura des cas où ce n'est pas la meilleure chose à faire (spécialement pour les critères de recherche très complexes).

9
répondu luis.espinal 2017-01-26 17:38:18
la source

Comme je suis à l'aide d'un laravel/php backend, j'ai tendance à aller avec quelque chose comme ceci:

/resource?filters[status_id]=1&filters[city]=Sydney&page=2&include=relatedResource

PHP transforme automatiquement [] params en tableau, donc dans cet exemple je vais finir avec une variable $filter qui contient un tableau/objet de filtres, ainsi qu'une page et toutes les ressources connexes que je veux eager chargé.

Si vous utilisez une autre langue, cela peut être une bonne convention et vous pouvez créer un parser pour convertir [] en tableau.

7
répondu the-a-train 2018-06-22 20:37:50
la source

FYI: je sais que c'est un peu tard mais pour quiconque est intéressé. Cela dépend de la façon dont vous voulez vous reposer, vous devrez mettre en œuvre vos propres stratégies de filtrage car les spécifications HTTP ne sont pas très claires à ce sujet. Je voudrais suggérer url-encoding tous les paramètres de filtre par exemple

GET api/users?filter=param1%3Dvalue1%26param2%3Dvalue2

je sais que c'est laid mais je pense que c'est la façon la plus reposante de le faire et devrait être facile à analyser du côté du serveur:)

2
répondu shanks 2017-04-21 14:02:46
la source

Autres questions sur design search rest api filter