146

I am building a REST API for my project. The API for getting a given user's INFO is:

api.com/users/[USER-ID]

I would like to also allow the client to pass in a list of user IDs. How can I construct the API so that it is RESTful and takes in a list of user ID's?

Henke
  • 4,445
  • 3
  • 31
  • 44
uclajatt
  • 4,003
  • 4
  • 21
  • 11
  • The most generic answer is given by @Shuja, cause other answers from postman didn't work and are dependent on the database backend. However, you can have an API end-point to request for multiple id's. – Eswar Jan 22 '19 at 12:50

6 Answers6

118

If you are passing all your parameters on the URL, then probably comma separated values would be the best choice. Then you would have an URL template like the following:

api.com/users?id=id1,id2,id3,id4,id5
Florin Dumitrescu
  • 8,182
  • 4
  • 33
  • 29
  • 2
    The problem with this approach is that it doesnt' seem restful. For example if I want to get the friends of this list of users – uclajatt Dec 27 '10 at 21:26
  • 8
    @uclajatt, REST is an architectural model and not a protocol and if you study the major REST APIs available today, you will see that there are multiple ways of implementing it. The approach that I am suggesting is probably one of the closest to the concept since it accomplishes all the constraints described here: http://en.wikipedia.org/wiki/Representational_State_Transfer#Constraints. You would only use CSV to represent arrays in requests, while the service responses should be serialized using XML or JSON. Are there any particular reasons why you don't consider my approach to be REST? – Florin Dumitrescu Dec 28 '10 at 15:40
  • 3
    Florin's answer is the actual way the OpenSocial API uses. – emeraldhieu Jun 11 '12 at 13:06
  • 1
    This approach seems fine in the circumstance. Just for info: some versions of (crosses fingers, as if to ward off a vampire) IE reject urls with comma-separated parameters. Usually not an issue, but just to know about this when you are testing... Other browsers work fine. – vikingsteve May 15 '13 at 12:00
  • 11
    Why not this? api.com/users?id=id1&id=id2&id=id3&id=id4&id=id5 – senfo Jun 26 '13 at 14:37
  • 10
    @senfo, I prefer id=id1,id2,id3 because it makes the URI shorter and easier to read (by a human, during a debugging operation for example). Individual parameters for each value would make the URI especially harder to follow if there are other parameters between ids: api.com/users?id=id1&id=id2&joined-after=2013-01-01&id=id3 – Florin Dumitrescu Jan 23 '14 at 12:13
  • 1
    @FlorinDumitrescu fair enough... ;-) – senfo Jan 23 '14 at 22:57
  • @FlorinDumitrescu How can I extract the ids from array (declared in javascript) and put them that way in a url ? – Sahar Ch. May 30 '14 at 15:27
  • @SaharCh. "id="+arr.join(",") – w00t Mar 26 '15 at 12:49
  • One note about this approach is the way parameters are noted in various frameworks. For example: JAX-RS: @Path('/items/{id}') versus @Path('/items'} - mean totally different things. – thinice Feb 11 '16 at 04:49
  • 26
    However, most web servers support the URL length of about 2,000 bytes. How to make my API support up to 5,000 ids? – nicky_zs Mar 28 '16 at 11:48
  • 12
    @senfo In URLs like `…?id=1&id=2&id=3`, [there is no guarantee](http://stackoverflow.com/q/1746507/578288) that duplicate query parameters will be combined into an array. With the above query string, PHP happens to tell you that `id` equals `[1, 2, 3]`, but Ruby on Rails tells you it equals `3`, and other frameworks may also act differently, e.g. saying `id` equals `1`. URLs like `…?id=1,2,3` avoid this potential for confusion. – Rory O'Kane Nov 16 '16 at 16:33
  • @FlorinDumitrescu the URL given cannot be generic because it depends on the database being used at the back-end. Because for me using mongoDB, this url produces only the last id given.. – Eswar Jan 22 '19 at 12:39
  • URL id lists defeat HTTP caches. For example, GETs to /id=1,2,3 /id=3,2,1 and /id=2,3,1 all return the same semantic results, but intermediate HTTP services, like caches, can't tell them apart. This can be mitigated by expecting sorted order, but this still floods any cache with all the permutations of ids. I suggest setting appropriate cache headers in the response (to indicate that it should not be cached.) – allenru Oct 21 '19 at 02:38
  • i just don't see the need for querystring... the CSV list can be part of the path – Reinsbrain Jul 04 '22 at 16:42
45
 api.com/users?id=id1,id2,id3,id4,id5
 api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

IMO, above calls does not looks RESTful, however these are quick and efficient workaround (y). But length of the URL is limited by webserver, eg tomcat.

RESTful attempt:

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

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

Server will reply URI of newly created batchtask resource.

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

Now client can fetch batch response or task progress by polling

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


This is how others attempted to solve this issue:

Community
  • 1
  • 1
Nilesh
  • 2,089
  • 3
  • 29
  • 53
  • 11
    POST request to _get_ multiple results is not RESTful. Your example shows creating a resource, where it is appropriate to POST, but that is a totally different case to the original question – Anentropic Jun 30 '16 at 14:22
  • 4
    Creating temporary resource is RESTful, isnt it? And I am getting resources using GET, its again RESTful. – Nilesh Jun 30 '16 at 14:37
  • yes, but none of that was in the original question, which just asks about getting info for multiple user ids – Anentropic Jun 30 '16 at 14:45
  • 1
    Thanks @Anentropic for pointing out. I read the question again it asks _How to construct a REST API that takes an array of id's for the resources ?_ and I agree, my answer is different. Sorry for not getting your point. – Nilesh Jul 01 '16 at 05:28
  • I like this answer as the RESTful way to get multiple users is via this mechanism. – Shane Courtrille Nov 04 '16 at 20:13
  • @Nilesh how do you say that the above calls are not restful?? – Eswar Jan 22 '19 at 12:44
  • 1
    It might violate Cacheability REST principle. Caching such requests is difficult. If we cache responses to such batch requests then invalidating is difficult. – Nilesh Jan 23 '19 at 06:16
  • good solution where the batch is allowed or desirable to be large – Reinsbrain Jul 04 '22 at 16:44
26

I find another way of doing the same thing by using @PathParam. Here is the code sample.

@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.
}

Call the service by using following url.

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

where

http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76
Holger Just
  • 52,918
  • 14
  • 115
  • 123
David
  • 481
  • 5
  • 14
  • 5
    I like this one because the GET is consistent. You can use one number or many in this example. And it is not really a search (parameters), as you are giving the back end the exact ids you want. – markthegrea Sep 12 '12 at 18:12
  • 1
    I see the most upvoted answer doesn't work and your answer is probably the most generic one. Should be accepted as the answer. – Eswar Jan 22 '19 at 12:48
24

As much as I prefer this approach:-

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

The correct way is

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

or

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

This is how rack does it. This is how php does it. This is how node does it as well...

Community
  • 1
  • 1
Kyristopher
  • 425
  • 4
  • 4
0

There seems to be a few ways to achieve this. I'd like to offer how I solve it:

GET /users/<id>[,id,...]

It does have limitation on the amount of ids that can be specified because of URI-length limits - which I find a good thing as to avoid abuse of the endpoint.

I prefer to use path parameters for IDs and keep querystring params dedicated to filters. It maintains RESTful-ness by ensuring the document responding at the URI can still be considered a resource and could still be cached (although there are some hoops to jump to cache it effectively).

I'm interested in comments in my hunt for the ideal solution to this form :)

Reinsbrain
  • 2,235
  • 2
  • 23
  • 35
-2

You can build a Rest API or a restful project using ASP.NET MVC and return data as a JSON. An example controller function would be:

        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));
        }

Then you just call the GetUsers function via a regular AJAX function supplying the array of Ids(in this case I am using jQuery stringify to send the array as string and dematerialize it back in the controller but you can just send the array of ints and receive it as an array of int's in the controller). I've build an entire Restful API using ASP.NET MVC that returns the data as cross domain json and that can be used from any app. That of course if you can use 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
  • 699
  • 7
  • 16
  • 5
    Sorry, I wasnt' asking for how to implement the API. I was just asking of how to construct the API URI so that the client can access info about an array of users. I can pass id's via query parameters, but I believe that wont' be very restful. – uclajatt Dec 27 '10 at 20:54
  • @uclajatt Why do you think that is not RESTful? – Darrel Miller Dec 27 '10 at 21:18
  • 1
    I believe passing id's or any other values via query parameters is indeed a restful approach of interacting with a system. How you construct you Uri it's up to you. Being it users/all, users/array, array/users or any other naming convention you feel that makes sense. Taking in consideration how the MVC framework works its very easy to use it for building a restful API as you can organize and build you Uris just as you need them.Once you have your Uris, you can pass you parameters using AJAX as one string, or as multiple values if your are using a form and doing a post to an MVC action. – Vasile Laur Dec 28 '10 at 02:32
  • 1
    @uclajatt Thats twice now you've been asked on this post why you think passing a comma seperated list in a query parameter is not RESTful and you don't even bother to answer it, let alone accept any of these very plausible solutions !?! Not cool. – samus Aug 13 '12 at 15:27