115

I'm trying to design a RESTful API where the users can fetch a single product or list of products in a single GET request. Each product has a unique id.

The single product URL is simple enough:

http://mycompany.com/api/v1/product/id

This returns the information for a single product. I'm confused as to how the URL for multiple product information should look like.

How about

http://mycompany.com/api/v1/product/ids

where ids is a comma separated list of ids?

observer
  • 2,925
  • 1
  • 19
  • 38
user824212
  • 1,277
  • 3
  • 10
  • 11

2 Answers2

204

I would recommend thinking of it like you are listing multiple representations of the resource filtered by id. As such you make a GET request to the base resource:

https://example.com/api/v1/products

And filter the response list by id:

https://example.com/api/v1/products?id=1,2,3

abraham
  • 46,583
  • 10
  • 100
  • 152
  • 38
    This is the superior answer imho, reason being: `/products` and `products?id=1,2,3` will give __consistent__ responses (=collection resources). Comparing `/products/1` and `/products/1,2,3` is a recipe for client headaches - unless of course all nested endpoints return collections by default (which is also an interesting approach, for an example see the [api+json](http://jsonapi.org/) format) – Philzen Jul 30 '14 at 14:24
  • 2
    I like this approach, but shouldn't it be https://example.com/api/v1/products?id=1&id=2&id=3 ? – Nitek Nov 14 '16 at 09:18
  • 10
    @Nitek No; [there is no guarantee](http://stackoverflow.com/q/1746507/578288) that duplicate query parameters will be combined into an array. For your example URL, PHP would indeed tell you that `id` equals `[1, 2, 3]`, but Ruby on Rails would tell you it equals `3`, and other frameworks may also act differently, e.g. saying `id` equals `1`. – Rory O'Kane Nov 16 '16 at 16:20
  • Can we also the same pattern for returning all data, like using an endpoint like `products?id=` where `id` have empty list. Will it be correct to return all products in this case? – Shubham A. Feb 01 '18 at 09:15
  • 6
    I would expect `products?id=` to return no results and `products` to return all results. – abraham Feb 02 '18 at 23:28
  • Why not use `ids` instead of `id`, eg, `https://example.com/api/v1/products?ids=1,2,3`? – ma11hew28 Sep 08 '18 at 22:47
  • 1
    @ma11hew28 because `id` is the field on the object being matched against. – abraham Sep 16 '18 at 21:11
  • What should we do if want to get a multiple subresources? Accessing a single subresource would be easy: `/v1/products/1234/customers`, but how would we get a list of the customer resources across 2 (or more) products? We could do it with two calls easily, but what if that list goes to 20+? – Shadoninja Apr 02 '20 at 14:55
  • @Shadoninja if what you are listing is `customers` you should probably have that as the base resource. `/v1/customers?product_id=1,2,3` – abraham Apr 03 '20 at 17:01
  • @abraham That is a good idea. Thanks – Shadoninja Apr 04 '20 at 18:30
  • I always refer to existing well known API's that have implemented REST well, for example https://docs.gitlab.com/ee/api/users.html. This provides a good example of how to search resources, `users` in this case. In the search user endpoint, the resource ID becomes a query string instead where you can specify the attributes (I.e. criteria) to search users based on. – Jose Quijada Dec 20 '21 at 14:45
  • How about if the id is GUID??? – huang Feb 20 '22 at 01:27
  • The value of the ID doesn't matter as long as it stays within URL length limits and is properly encoded. – abraham Feb 20 '22 at 14:48
  • What about pass it in the body? – Yedidya Rashi Sep 05 '22 at 10:02
70

Your suggestion of ids separated with commas is good enough.

It would be instructive to examine some public REST APIs to see how they handle. For ex, the StackExchange API separates ids with a semi-colon - https://api.stackexchange.com/docs/answers-by-ids

Andy Davies
  • 666
  • 9
  • 23
aldrin
  • 4,482
  • 1
  • 33
  • 50
  • 2
    I wonder why people don't use products?id[]=1&id[]=2. URL parsers handle this just fine. – Julio Greff Feb 29 '12 at 20:22
  • 13
    @JulioGreff I think, it's because it just looks a bit ugly. No other particular reason. – Denis V Jun 07 '14 at 09:25
  • 8
    @JulioGreff RESTful api's don't just select by id, they also decorate. example `/api/dogs/fluffy1234` could be extended to do more things like this: `/api/dogs/fluffy1234/siblings` and so, if you can keep the selector logic in the same place where the ID would normally go, then you can still use your decorators – Kristian Apr 26 '15 at 05:48
  • This is the example, https://api.stackexchange.com/2.2/answers/12%3B13%3B14?site=stackoverflow – foxiris Apr 15 '20 at 03:05
  • 1
    Performance can also be better with a series of "GET product" requests because the server's response time for an aggregated query is NEVER faster than the lookup of the product that takes LONGEST to return. Plus, you cannot indicate "some items not found" as a response code, which usually leads to dirty workarounds like usage of WebDAV's HTTP 207 – observer Jan 18 '22 at 21:27