466

I want to make my RESTful API very predictable. What is the best practice for deciding when to make a segmentation of data using the URI rather than by using query params.

It makes sense to me that system parameters that support pagination, sorting, and grouping be after the '?' But what about fields like 'status' and 'region' or other attributes that segment your collection? If those are to be query params as well, what is the rule of thumb on knowing when to use path params?

cosbor11
  • 14,709
  • 10
  • 54
  • 69
  • 1
    a similar question is answered here ... http://stackoverflow.com/questions/3198492/rest-standard-path-parameters-or-request-parameters – Lalit Mehra Jun 21 '15 at 18:33

8 Answers8

736

TL;DR: Best practice for RESTful API design is that path params are used to identify a specific resource or resources, while query parameters are used to sort/filter those resources.


Here's an example. Suppose you are implementing RESTful API endpoints for an entity called Car. You would structure your endpoints like this:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
DELETE /cars/:id

This way you are only using path parameters when you are specifying which resource to fetch, but this does not sort/filter the resources in any way.

Now suppose you wanted to add the capability to filter the cars by color in your GET requests. Because color is not a resource (it is a property of a resource), you could add a query parameter that does this. You would add that query parameter to your GET /cars request like this:

GET /cars?color=blue

This endpoint would be implemented so that only blue cars would be returned.

We can add more filtering parameters using the & symbol:

GET /cars?color=blue&brand=ferrari

As far as syntax is concerned, your URL names should be all lowercase. If you have an entity name that is generally two words in English, you would use a hyphen to separate the words, not camel case.

Ex. /two-words

Mike
  • 10,297
  • 2
  • 21
  • 21
  • 6
    Thank you for your answer Mike. This is a clearcut and simple methodology; worth an up vote from me. Still, oftentimes, developers opt for the 'cars/blue' approach, I'm wondering what their reasoning is for doing so... perhaps they decide to make path params for fields that are mandatory, or maybe they do it to indicate that the database is partitioned by that shard. – cosbor11 Jul 07 '15 at 06:52
  • 6
    I am not sure what their reasoning is. Honestly, I disagree with it. I think following conventions and keeping it simple makes the most sense. By doing so, you allow the consumers of your API to better understand exactly what they need to do to access it's functionality. – Mike Jul 12 '15 at 17:16
  • 5
    what about /cars?id=1&color=blue instead of cars/1/?color=blue. you are basically filtering cars resource in each scenario – mko Nov 24 '17 at 13:38
  • 13
    Wrong since car with id 1 only exist one but cars with color blue maybe many. There is the distinction between identity and filter – paul Dec 13 '17 at 20:52
  • 2
    My hypothesis as to why using path params is so widespread is because many developers learned from frameworks designed by people who didn't have a good grasp of REST principles (Ruby on Rails in particular.) – Chris Broski Jan 12 '18 at 13:56
  • 41
    Fun trivia, `this-is-called-kebab-case` – le3th4x0rbot Feb 02 '19 at 00:57
  • 1
    I’ve to generate daily and weekly reports for users. So should I use `/users/user_id/reports/daily?day=2020-03-14` and `/users/user_id/reports/weekly?week=13` or `/users/user_id/reports?type=daily&day=2020-03-14` and `/users/user_id/reports?type=weekly&week=13`. These reports do not point to one particular resource, rather the report is generated based on several entries in DB table. – Raghavendra N Mar 15 '20 at 12:17
  • what about if you have a pk with two fields and you want to get it? ie: /cars GET (List) and /cars/:id where you have id and otherId? – Elliot Dec 15 '21 at 18:57
  • When i want to open a car in edit mode, should i send the eidt flag as path or query parameter? Or is there any other way to communicate such edit modes to destination page. – Braj Apr 24 '22 at 05:34
  • I think path parameters are frivolous and should be done away with. It would reduce both confusion and code. It adds no practical value other than philosophy. Query parameters are sufficient for both identification and filtering. – Aditya Mittal May 22 '22 at 17:42
157

The fundamental way to think about this subject is as follows:

A URI is a resource identifier that uniquely identifies a specific instance of a resource TYPE. Like everything else in life, every object (which is an instance of some type), have set of attributes that are either time-invariant or temporal.

In the example above, a car is a very tangible object that has attributes like make, model and VIN - that never changes, and color, suspension etc. that may change over time. So if we encode the URI with attributes that may change over time (temporal), we may end up with multiple URIs for the same object:

GET /cars/honda/civic/coupe/{vin}/{color=red}

And years later, if the color of this very same car is changed to black:

GET /cars/honda/civic/coupe/{vin}/{color=black}

Note that the car instance itself (the object) has not changed - it's just the color that changed. Having multiple URIs pointing to the same object instance will force you to create multiple URI handlers - this is not an efficient design, and is of course not intuitive.

Therefore, the URI should only consist of parts that will never change and will continue to uniquely identify that resource throughout its lifetime. Everything that may change should be reserved for query parameters, as such:

GET /cars/honda/civic/coupe/{vin}?color={black}

Bottom line - think polymorphism.

cosbor11
  • 14,709
  • 10
  • 54
  • 69
Kingz
  • 5,086
  • 3
  • 36
  • 25
  • 4
    Interesting paradigm.. Is this a commonly used design patten? Can you provide some APIs that use this in their documentation or some references that outline this strategy? – cosbor11 Jun 07 '17 at 20:25
  • 2
    I like how you emphasized "TYPE" when you wrote "A URI is a resource identifier that uniquely identifies a specific instance of a resource TYPE". I think that's an important distinction. – jmrah Oct 13 '17 at 14:55
  • this makes most sense. I think path variables helps parameters to be cleaner and more understandable. – Jonathan Hagen Sep 25 '20 at 18:45
  • 3
    This is a very good point, and rule, in REST-API design: `URI should only consist of parts that will never change and will continue to uniquely identify that resource throughout its lifetime` – kravemir Dec 23 '20 at 11:21
30

In a REST API, you shouldn't be overly concerned by predictable URI's. The very suggestion of URI predictability alludes to a misunderstanding of RESTful architecture. It assumes that a client should be constructing URIs themselves, which they really shouldn't have to.

However, I assume that you are not creating a true REST API, but a 'REST inspired' API (such as the Google Drive one). In these cases the rule of thumb is 'path params = resource identification' and 'query params = resource sorting'. So, the question becomes, can you uniquely identify your resource WITHOUT status / region? If yes, then perhaps its a query param. If no, then its a path param.

user1717828
  • 7,122
  • 8
  • 34
  • 59
Oliver McPhee
  • 1,010
  • 10
  • 18
  • 34
    I disagree, a good API should be predictable; RESTful or otherwise. – cosbor11 Jun 30 '15 at 19:22
  • When you say 'a good API should be predictable', do you mean the URI's should be predictable? If so, why is that important in a RESTful API? – Oliver McPhee Jul 01 '15 at 14:26
  • 4
    I think so. There should be rhyme and reason to how the URI is formed, rather than arbitrarily naming endpoints. When one can intuitivly write an API client without constantly referencing the documentation, you've written a good API in my opinion. – cosbor11 Jul 01 '15 at 16:53
  • 4
    "When one can intuitivly write an API client without constantly referencing the documentation". That is where I think our understanding of REST differs... the API client should never need to 'build' a URL. They should select it from the response of the previous API call. If you take a website as an analogy... You go to facebook.com, then you select a link to the events page. You dont care whether the facebook events URL is 'predictable', as you arent typing it in. You get there via hypermedia links. The same is true of a REST api. So, make URIs meaningful to you (the server), but not th client – Oliver McPhee Jul 02 '15 at 12:38
  • 2
    Added note. This doesn't mean that the URIs shouldn't follow an easy to understand pattern, it just means that its not a constraint of a RESTful API. The biggest issue with this area is people assuming that a client should build the URLs themselves. They shouldnt, as that creates a coupling between client and server that shouldnt exist. (eg - the server cannot then change a URL without breaking all client applications). In a REST API, the server can change them as it pleases. – Oliver McPhee Jul 02 '15 at 13:07
  • 10
    +1 for using the following words: "'path params = resource identification' and 'query params = resource sorting'". This really cleared it up for me. – Doug Jun 27 '17 at 09:20
  • What if you need to validate your resource identifier? – Austin Born Jul 07 '22 at 16:22
13

Segmentation is more hierarchal and "pretty" but can be limiting.

For example, if you have a url with three segments, each one passing different parameters to search for a car via make, model and color:

www.example.com/search/honda/civic/blue

This is a very pretty url and more easily remembered by the end user, but now your kind of stuck with this structure. Say you want to make it so that in the search the user could search for ALL blue cars, or ALL Honda Civics? A query parameter solves this because it give a key value pair. So you could pass:

www.example.com/search?color=blue
www.example.com/search?make=civic

Now you have a way to reference the value via it's key - either "color" or "make" in your query code.

You could get around this by possibly using more segments to create a kind of key value structure like:

www.example.com/search/make/honda/model/civic/color/blue

Hope that makes sense..

webmaster_sean
  • 942
  • 4
  • 13
  • 23
  • I think this is where the concept of a resource comes in. A make and a colour are not resources. `/cars` is a resource. Maybe if you have different garages that sell cars then `/cars/[garage]/` is a resource. Then you could search for make and colour across all cars or make and colour in a garage. – icc97 Apr 07 '22 at 13:57
  • Supplying key-value filter parameters in url paths is a bad design. That's what querystring is for. Url paths are better suited for hierarchical queries. – xyres Dec 14 '22 at 17:27
9

Once I designed an API which main resource was people. Usually users would request filtered people so, to prevent users to call something like /people?settlement=urban every time, I implemented /people/urban which later enabled me to easily add /people/rural. Also this allows to access the full /people list if it would be of any use later on. In short, my reasoning was to add a path to common subsets

From here:

Aliases for common queries

To make the API experience more pleasant for the average consumer, consider packaging up sets of conditions into easily accessible RESTful paths. For example, the recently closed tickets query above could be packaged up as GET /tickets/recently_closed

Community
  • 1
  • 1
Mario Gil
  • 493
  • 1
  • 5
  • 14
9

Consider the word "path" - a way to get to a location. Path parameters should describe how to get to the location/resource that you interested in. This includes directories, IDs, files, etc.

/vehicles/cars/vehicle-id-1

Here, vehicle-id-1 is a path parameter.

Consider the word "query" - I think of it as asking a question about the path i.e. is my path blue, does my path have 100 results.

/vehicles/cars/vehicle-id-1?color=blue&limit=100

Here color=blue and limit=100 are the query parameters, which help describe what we should do once we get to our resource: filter out blue ones, and limit them by 100 results.

Janac Meena
  • 3,203
  • 35
  • 32
2

Generally speaking, I tend to use path parameters when there is an obvious 'hierarchy' in the resource, such as:

/region/state/42

If that single resource has a status, one could:

/region/state/42/status

However, if 'region' is not really part of the resource being exposed, it probably belongs as one of the query parameters - similar to pagination (as you mentioned).

morsor
  • 1,263
  • 14
  • 29
-10

Example URL: /rest/{keyword}

This URL is an example for path parameters. We can get this URL data by using @PathParam.

Example URL: /rest?keyword=java&limit=10

This URL is an example for query parameters. We can get this URL data by using @Queryparam.

Grant Foster
  • 722
  • 2
  • 11
  • 21
Sujithrao
  • 789
  • 3
  • 12
  • 27
  • 9
    The question was "when" to use them not "how" to use them. Also, the @ PathParam and @ QueryParam are language specific and therefore not helpful but to a select group of people. – Simon Taylor Jan 24 '22 at 23:54