Comment construire une API REST qui prend un tableau d'identifiants pour les ressources

103

Je construis une API REST pour mon projet. L'API pour obtenir l'INFO d'un utilisateur donné est:

api.com/users/[USER-ID]

Je voudrais également permettre au client de transmettre une liste d'identifiants d'utilisateurs. Comment puis-je construire l'API de manière à ce qu'elle soit RESTful et intègre une liste d'ID utilisateur?

uclajatt
la source
La réponse la plus générique est donnée par @Shuja, car les autres réponses du facteur n'ont pas fonctionné et dépendent du backend de la base de données. Cependant, vous pouvez avoir un point de terminaison API pour demander plusieurs identifiants.
Eswar

Réponses:

97

Si vous passez tous vos paramètres sur l'URL, des valeurs séparées par des virgules seraient probablement le meilleur choix. Ensuite, vous auriez un modèle d'URL comme le suivant:

api.com/users?id=id1,id2,id3,id4,id5
Florin Dumitrescu
la source
7
@uclajatt, REST est un modèle architectural et non un protocole et si vous étudiez les principales API REST disponibles aujourd'hui, vous verrez qu'il existe plusieurs façons de l'implémenter. L'approche que je propose est probablement l'une des plus proches du concept puisqu'elle accomplit toutes les contraintes décrites ici: en.wikipedia.org/wiki/… . Vous utiliseriez uniquement CSV pour représenter des tableaux dans les requêtes, tandis que les réponses de service doivent être sérialisées à l'aide de XML ou JSON. Y a-t-il des raisons particulières pour lesquelles vous ne considérez pas mon approche comme REST?
Florin Dumitrescu
10
Pourquoi pas ça? api.com/users?id=id1&id=id2&id=id3&id=id4&id=id5
senfo
7
@senfo, je préfère id = id1, id2, id3 car cela rend l'URI plus court et plus facile à lire (par un humain, lors d'une opération de débogage par exemple). Des paramètres individuels pour chaque valeur rendraient l'URI particulièrement difficile à suivre s'il y avait d'autres paramètres entre les identifiants: api.com/users?id=id1&id=id2&joined-after=2013-01-01&id=id3
Florin Dumitrescu
12
Cependant, la plupart des serveurs Web prennent en charge une longueur d'URL d'environ 2 000 octets. Comment faire en sorte que mon API supporte jusqu'à 5000 identifiants?
nicky_zs
6
@senfo Dans les URL comme …?id=1&id=2&id=3, il n'y a aucune garantie que les paramètres de requête en double seront combinés dans un tableau. Avec la chaîne de requête ci-dessus, PHP arrive à vous dire que idégale [1, 2, 3], mais Ruby on Rails vous dit que c'est égal 3, et d'autres frameworks peuvent également agir différemment, par exemple en disant idégal 1. Les URL comme …?id=1,2,3évitent ce potentiel de confusion.
Rory O'Kane
33
 api.com/users?id=id1,id2,id3,id4,id5
 api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

IMO, les appels ci-dessus ne semblent pas RESTful, mais il s'agit d'une solution de contournement rapide et efficace (y). Mais la longueur de l'URL est limitée par le serveur Web, par exemple tomcat .

Tentative de repos:

POST http://example.com/api/batchtask

   [
    {
      method : "GET",
      headers : [..],
      url : "/users/id1"
    },
    {
      method : "GET",
      headers : [..],
      url : "/users/id2"
    }
   ]

Le serveur répondra à l'URI de la ressource batchtask nouvellement créée .

201 Created
Location: "http://example.com/api/batchtask/1254"

Le client peut maintenant récupérer la réponse par lots ou la progression de la tâche en interrogeant

GET http://example.com/api/batchtask/1254


Voici comment d'autres ont tenté de résoudre ce problème:

Nilesh
la source
7
La requête POST pour obtenir plusieurs résultats n'est pas RESTful. Votre exemple montre la création d'une ressource, où il est approprié de POST, mais c'est un cas totalement différent de la question d'origine
Anentropic
2
La création d'une ressource temporaire est RESTful, n'est-ce pas? Et j'obtiens des ressources en utilisant GET, c'est à nouveau RESTful.
Nilesh
oui, mais rien de tout cela ne figurait dans la question d'origine, qui demande simplement d'obtenir des informations pour plusieurs identifiants d'utilisateurs
Anentropic
1
Merci @Anentropic pour l'avoir signalé. J'ai relu la question qu'elle pose: Comment construire une API REST qui prend un tableau d'identifiants pour les ressources? et je suis d'accord, ma réponse est différente. Désolé de ne pas avoir compris votre point.
Nilesh
J'aime cette réponse car le moyen RESTful d'obtenir plusieurs utilisateurs est via ce mécanisme.
Shane Courtrille
20

Je trouve une autre façon de faire la même chose en utilisant @PathParam. Voici l'exemple de code.

@GET
@Path("data/xml/{Ids}")
@Produces("application/xml")
public Object getData(@PathParam("zrssIds") String Ids)
{
  System.out.println("zrssIds = " + Ids);
  //Here you need to use String tokenizer to make the array from the string.
}

Appelez le service en utilisant l'URL suivante.

http://localhost:8080/MyServices/resources/cm/data/xml/12,13,56,76

http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76
Shuja
la source
5
J'aime celui-ci car le GET est cohérent. Vous pouvez utiliser un ou plusieurs nombres dans cet exemple. Et ce n'est pas vraiment une recherche (paramètres), car vous donnez au back-end les identifiants exacts que vous voulez.
markthegrea
1
Je vois que la réponse la plus votée ne fonctionne pas et votre réponse est probablement la plus générique. Devrait être accepté comme réponse.
Eswar
18

Autant que je préfère cette approche: -

    api.com/users?id=id1,id2,id3,id4,id5

La bonne façon est

    api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

ou

    api.com/users?ids=id1&ids=id2&ids=id3&ids=id4&ids=id5

C'est ainsi que le rack procède. Voici comment php le fait. C'est ainsi que node le fait aussi ...

Kyristopher
la source
19
Je ne suis pas sûr que faire référence aux normes PHP comme ligne directrice à suivre soit le meilleur conseil. eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design
trebor
Ce n'est pas ainsi que Flask procède.
jscul
0

Vous pouvez créer une API Rest ou un projet reposant à l'aide d'ASP.NET MVC et renvoyer des données sous forme de JSON. Un exemple de fonction de contrôleur serait:

        public JsonpResult GetUsers(string userIds)
        {
           var values = JsonConvert.DeserializeObject<List<int>>(userIds);

            var users = _userRepository.GetAllUsersByIds(userIds);

            var collection = users.Select(user => new { id = user.Id, fullname = user.FirstName +" "+ user.LastName });
            var result = new { users = collection };

            return this.Jsonp(result);
        }
        public IQueryable<User> GetAllUsersByIds(List<int> ids)
        {
            return _db.Users.Where(c=> ids.Contains(c.Id));
        }

Ensuite, vous appelez simplement la fonction GetUsers via une fonction AJAX régulière fournissant le tableau d'ID (dans ce cas, j'utilise jQuery stringify pour envoyer le tableau sous forme de chaîne et le dématérialiser dans le contrôleur, mais vous pouvez simplement envoyer le tableau d'entiers et recevoir comme un tableau d'entiers dans le contrôleur). J'ai construit une API Restful entière à l'aide d'ASP.NET MVC qui renvoie les données sous forme de json interdomaine et qui peut être utilisée à partir de n'importe quelle application. Cela bien sûr si vous pouvez utiliser ASP.NET MVC.

function GetUsers()
    {
           var link = '<%= ResolveUrl("~")%>users?callback=?';
           var userIds = [];
            $('#multiselect :selected').each(function (i, selected) {
                userIds[i] = $(selected).val();
            });

            $.ajax({
                url: link,
                traditional: true,
                data: { 'userIds': JSON.stringify(userIds) },
                dataType: "jsonp",
                jsonpCallback: "refreshUsers"
            });
    }
Vasile Laur
la source
3
Désolé, je n'ai pas demandé comment implémenter l'API. Je demandais juste comment construire l'URI de l'API afin que le client puisse accéder aux informations sur un tableau d'utilisateurs. Je peux transmettre des identifiants via des paramètres de requête, mais je pense que cela ne sera pas très reposant.
uclajatt
@uclajatt Pourquoi pensez-vous que ce n'est pas RESTful?
Darrel Miller
1
Je crois que passer des identifiants ou toute autre valeur via des paramètres de requête est en effet une approche reposante d'interaction avec un système. Comment vous construisez-vous Uri c'est à vous. Qu'il s'agisse d'utilisateurs / tous, utilisateurs / tableau, tableau / utilisateurs ou toute autre convention de dénomination qui vous semble logique. En tenant compte du fonctionnement du framework MVC, il est très facile de l'utiliser pour créer une API reposante car vous pouvez organiser et créer vos Uris comme vous en avez besoin.Une fois que vous avez vos Uris, vous pouvez passer vos paramètres en utilisant AJAX comme une chaîne, ou sous forme de valeurs multiples si vous utilisez un formulaire et publiez une action MVC.
Vasile Laur
1
@uclajatt C'est deux fois maintenant qu'on vous a demandé sur ce post pourquoi vous pensez que passer une liste séparée par des virgules dans un paramètre de requête n'est pas RESTful et que vous ne prenez même pas la peine d'y répondre, et encore moins d'accepter l'une de ces solutions très plausibles!? ! Pas cool.
samis