How to configure query parameters in Spring Controllers

In this post, we will discuss what query parameters are and how to configure them in a Spring controller using the @RequestParam annotation. We will also discuss how to set your query parameters as optional, how to configure multiple query parameters and more.

Before we start, I highly recommend that you check out our introductory tutorial to REST controllers in Spring Boot as reading it will make things easier to understand in this tutorial, especially for beginners.

Also keep in mind that the instructions provided in this post work for both Spring and Spring boot applications.

What are query parameters

When making a call to a controller, one can customize the behavior and the results that are produced by that endpoint by setting query parameters.

Query parameters are parameters that are passed on to an endpoint as a part of the URL during the web call. This could happen when browsing a website or when making a REST API call.

Breakdown of a an example URL in a browser. Note that in some cases, the URL also includes a path variable. However, this is not seen in this example for simplicity reasons.

In the diagram above, we highlighted the query parameters that exist in the browser’s URL field. In that example, we can see three different query parameters; “service”, “passive” and “rm”. You can indicate query parameters during your web call by using the “?” sign. Anything that comes after the question mark sign is considered a query parameter.

You can use the equal sign “=” to indicate the value of a query parameter. If you have more than one parameter in your call, then you can concatenate them using the “&” sign.

When we put all of this together, we get something that looks like this:

<host>/<endpoint>?queryparam1=value&queryparam2=value2&….

Query parameters are used to modify the behavior of the endpoint being called. For example, many REST endpoints accept an “order by” parameter which can be used to ask the endpoint to provide the result according to a specific order.

Another popular way of using query parameters is for pre-filtering the results. For example, if you are retrieving a list of employees and you want to get only the employees that have the first name “John”, then you can pass on a query parameter to filter by name, such as “?name=john”.

Just as the name suggests, query parameters, just like in any other query system are used to provide parameters to the query you are performing over your target endpoint.

When using query parameters, make sure that you are percentage encoding (also known as URL Encoding) the values. This is needed when your values have special characters. If you are making the call in a modern browser, this will be automatically done for you. However, you need to take care of this if you are calling these endpoints from your own application. You can read more about percentage encoding in this Wikipedia article.

How to configure query parameters in Spring controllers

Configuring query parameters in Spring is quite simple. Before we start, please keep in mind that query parameters are called “Request parameters” in Spring MVC. This can be useful to know when searching through Spring documentation.

Let us build a quick example where we obtain a list of support tickets from a REST endpoints filtered by “status”.

First, let us get a quick overview of our model.


@Data
@NoArgsConstructor
@Entity
public class Ticket{

    @NotNull(groups = {DeletionValidationGroup.class, UpdateValidationGroup.class})
    @Min(value = 1, groups = {DeletionValidationGroup.class, UpdateValidationGroup.class})
    @Id
    @GeneratedValue
    public Long id;

    public String status;

    //some other fields here

If you are using Spring-Data, then you can easily implement a repository method which finds the “Ticket” entries based on their status.


package com.nullbeans.customerservice.incidentmanagement.data.repositories;

import com.nullbeans.customerservice.incidentmanagement.data.models.Ticket;
import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface TicketRepository extends CrudRepository<Ticket, Long> {

    List<Ticket> findTicketsByStatus(String status);

}

Now let us configure our controller’s method by configuring the endpoint to accept a parameter called “status” when calling the endpoint using the HTTP GET method.


@RestController
@RequestMapping(path = "/api/tickets")
public class TicketController {

    private TicketRepository ticketRepository;

    @GetMapping
    public Iterable<Ticket> getTickets(@RequestParam(required = false) String status){

        if(!StringUtils.isEmpty(status)) {
            return ticketRepository.findTicketsByStatus(status);
        }

        return ticketRepository.findAll();
    }

Let us go through the code example above. First, we annotated the status method parameter with the @RequestParam annotation to indicate to Spring that the value of the parameter should be obtained from the endpoint caller.

Notice that we configured the parameter with the required setting to false. This indicates to Spring that the parameter is not mandatory. This allows the caller to call the endpoint without providing the parameter for an unfiltered result set; or with the parameter to get the result list filtered by status. Note that request parameters are mandatory by default. If you do not indicate that the parameter is not required and the caller does not provide the value of the parameter, then Spring will throw an exception similar to the one below.

org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'status' is not present
	at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:204) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:114) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]

Let us try out our endpoint by calling the HTTP GET method using the URI: http://localhost:8081/api/tickets

[
      {
      "id": 1,
      "title": "first assigned ticket",
      "displayIdentifier": null,
      "description": null,
      "status": null,
      "organization": null,
      "assignedTicketQueue": null,
      "assignedUser": null
   },
      {
      "id": 5,
      "title": null,
      "displayIdentifier": null,
      "description": null,
      "status": "NEW",
      "organization": null,
      "assignedTicketQueue": null,
      "assignedUser": null
   },
      {
      "id": 6,
........................
..........................

As you can see, calling the endpoint without any request parameters will yield all the results in the database. So let us try again by providing the status query parameter by using the URI http://localhost:8081/api/tickets?status=CLOSED

[{
"id": 12,
"title": "My updated ticket",
"description": "I would like to learn REST in Spring",
"status": "CLOSED",
}]

Notice that this time we obtained a filtered result list.

Naming of query parameters

In our previous example, we did not explicitly set the name of the query parameter in the controller method. Therefore, the query parameter’s name was assumed by Spring to be the same as the method parameter name. However, this does not need to be the case.

You can configure the name of the parameter inside the @RequestParam annotation as follows.


    @GetMapping
    public Iterable<Ticket> getTickets(@RequestParam(required = false, name = "s") String status){

        if(!StringUtils.isEmpty(status)) {
            return ticketRepository.findTicketsByStatus(status);
        }

        return ticketRepository.findAll();
    }

Here, we named the parameter “s” instead of status. This can be useful when you are trying to avoid long URIs or when internal method argument names are secret or complicated.

Configuring multiple query parameters

Configuring multiple query parameters is the same as configuring a single query parameter. All you need to do is to annotated the method arguments whose values are are expected to be provided by the caller with the @RequestParam annotation.


    @GetMapping
    public Iterable<Ticket> getTickets(@RequestParam(required = false, name = "s") String status,
                                       @RequestParam(required = false, name = "t") String title){

Note that when calling the endpoint resource, you can provide your query parameters in any order. For example, you can provide the title parameter first and then the status parameter and vice versa.

Also note that the query parameters can co-exist with other method arguments whose values do not come from the caller, such as WebRequest, HttpRequest, or any other objects which are provided by Spring. The following code snippet is an example of such scenario.


    @GetMapping
    public Iterable<Ticket> getTickets(@RequestParam(required = false, name = "s") String status,
                                       @RequestParam(required = false, name = "t") String title,
                                        WebRequest request)

Query parameters datatypes

Query parameters can be of different datatypes. For example, you can use int to indicate an Integer datatype, or a boolean to indicate a boolean flag. However, it is highly advised to use the wrapper classes (Integer, Boolean, Short, etc..) for these datatypes in your method declarations.

    @GetMapping
    public Iterable<Ticket> getTickets(@RequestParam(required = false, name = "s") String status,
                                       @RequestParam(required = false, name = "p") Integer priority,
                                        WebRequest request)

Please avoid using the primitive datatypes in your controller method declarations as they are not compatible with optional parameters. If the user does not provide a value in a primitive field then Spring will not be able to handle the situation as it cannot fill primitive datatype variables with a null value. In such a scenario, you might encounter an exception like this:

java.lang.IllegalStateException: Optional int parameter 'p' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type.
	at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.handleNullValue(AbstractNamedValueMethodArgumentResolver.java:245) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:116) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]

Using Map as a query parameter

Another cool feature from Spring is the ability to declare a Map as a query parameter. When you add the @RequestParam to a method argument with the type Map<String, String> or MultiValueMap<String, String> and a parameter name is not specified, then the map will be populated by all query parameters that are provided by the caller. Let us check the following example.

    @GetMapping
    public Iterable<Ticket> getTickets(@RequestParam Map<String, String> queryParams)
    {
        String title = queryParams.get("title");
        boolean orderAsc = Boolean.parseBoolean(queryParams.get("Asc"));
        //do some things here..
        

If we call the endpoint above with the URI:

…api/tickets?title=Hello&Asc=true&status=NEW&….

then Spring will simply add all these request parameters to the map in the method arguments. You can then access these parameters by name inside your method as shown in the example.

Summary and further info

In this post, we discussed how to configure query parameters in a Spring application. Note that the techniques used in this tutorial apply to both MVC controllers and REST controllers.

Before you go, I would also like to remind you not to get confused between query parameters and path variables. Query parameters are parameters that are provided at the end of the URI after the ? symbol. On the other hand, path variables exist inside the resource path and are used for locating a specific resource or document. For example, the URI tickets/23/ has a path variable with the value 23.

We will talk more in depth about path variables in a later tutorial. For now, I hope you enjoyed this tutorial and thanks for reading!.