[rest] When do I use path params vs. query params in a RESTful API?

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?

The answer is


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


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.

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


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.


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.

HTH.


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.


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


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).


Examples related to rest

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Returning data from Axios API Access Control Origin Header error using Axios in React Web throwing error in Chrome JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value How to send json data in POST request using C# How to enable CORS in ASP.net Core WebAPI RestClientException: Could not extract response. no suitable HttpMessageConverter found REST API - Use the "Accept: application/json" HTTP Header 'Field required a bean of type that could not be found.' error spring restful API using mongodb MultipartException: Current request is not a multipart request

Examples related to spring-mvc

Two Page Login with Spring Security 3.2.x ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Spring 5.0.3 RequestRejectedException: The request was rejected because the URL was not normalized The type WebMvcConfigurerAdapter is deprecated RestClientException: Could not extract response. no suitable HttpMessageConverter found Spring boot: Unable to start embedded Tomcat servlet container UnsatisfiedDependencyException: Error creating bean with name 8080 port already taken issue when trying to redeploy project from Spring Tool Suite IDE Error creating bean with name 'entityManagerFactory' defined in class path resource : Invocation of init method failed Difference between the annotations @GetMapping and @RequestMapping(method = RequestMethod.GET)

Examples related to restful-url

When do I use path params vs. query params in a RESTful API? PUT and POST getting 405 Method Not Allowed Error for Restful Web Services How to access the services from RESTful API in my angularjs page? Passing array in GET for a REST call Hyphen, underscore, or camelCase as word delimiter in URIs? What’s the best RESTful method to return total number of items in an object?

Examples related to restful-architecture

When do I use path params vs. query params in a RESTful API? What is the difference between resource and endpoint? Passing array in GET for a REST call

Examples related to api-design

When do I use path params vs. query params in a RESTful API? What are best practices for REST nested resources? API pagination best practices What is the proper REST response code for a valid request but an empty data?