Retrofit 2 — Add Multiple Query Parameter With QueryMap

Adding request parameters can be kind of pain in the a** if your service methods allows multiple query parameters which also can be optional. We’ve published an article describing how to use optional query parameters. Today, we’re going to simplify the handling of multiple query parameters by introducing and using the @QueryMap annotation.

Retrofit Series Overview

What is @QueryMap in Retrofit?

Retrofit uses annotations to translate defined keys and values into appropriate format. Using the @Query("key") String value annotation will add a query parameter with name key and the respective string value to the request url (of course you can use other types than string :)).

Actually, there are APIs with endpoints allowing you to pass (optionally) multiple query parameters. You want to avoid a service method declaration like the one below with “endless” options for request parameters:

public interface NewsService() {  
    @GET("/news")
    Call<List<News>> getNews(
            @Query("page") int page,
            @Query("order") String order,
            @Query("author") String author,
            @Query("published_at") Date date,
            …
    );
}

You could call the .getNews service method with null values for each of the parameters to make them optional. Retrofit will ignore null values and don’t map them as query parameters. However, there is a better solution to work with complex API endpoints having various options for query parameters. Don’t worry, Retrofit got you covered!

How to Use QueryMap

The @QueryMap annotation expects a Map with key-value-pairs of type String. Each key which has a non-null value will be mapped and you can dynamically add your desired query parameters.

public interface NewsService() {  
    @GET("/news")
    Call<List<News>> getNews(
        @QueryMap Map<String, String> options
    );
}

If you want to request the news from page 2 of author Marcus, you only need to add the map entries for page and author. There’s no need to worry about the other available options.

The following snippet illustrates how to execute the actual request to fetch the news.

private void fetchNews() {  
    Map<String, String> data = new HashMap<>();
    data.put("author", "Marcus");
    data.put("page", String.valueOf(2));

    // simplified call to request the news with already initialized service
    Call<List<News>> call = newsService.getNews(data);
    call.enqueue(…);
}

The resulting url with the assumed example (page 2 of Marcus):

http://your.api.url/news?page=2&author=Marcus  

QueryMap Options

The @QueryMap annotation has an option field for encoding:

  • encoded: can be either true or false; default is false

You can set the value for encoding like this:

Call<List<News>> getNews((@QueryMap(encoded=true) Map<String, String> options);  

Enabling encoding will encode individual characters before appended to the request url. Using the key author with value marcus-poehls will result in the following encoded url: author=marcus%2Dpoehls.

Setting encoding to false (by default), the url for the example above would be author=marcus-poehls.

Outlook

Retrofit’s @QueryMap annotation is a convenient way to add multiple query parameters to a request without pre-defining their actual names. That gives you more freedom for requests by just passing the map with key-value-pairs to the service method, but doesn’t show you which options are available. It’s up to you to read the API documentation. We hope you’ve having a commendable backend developer :)

Explore the Library

Find interesting tutorials and solutions for your problems.