- Retrofit 2 – Query and Path parameters example
- 1.1. Single or multiple query parameters
- 1.2. Multiple query parameters with same name
- 1.3. Encoded query parameter
- 1.4. Optional query parameters
- 2.1. Simple path parameter
- 2.2. Encoded path parameter
- Use objects to pass multiple query parameters when making a request using Retrofit
- Resources
- Share this:
Retrofit 2 – Query and Path parameters example
Learn to perform requests with single, multiple and even optional query parameters and path parameters using @Query and @Path annotations in Retrofit 2.
Retrofit uses @Query annotation to define query parameters for requests. Query parameters are defined before method parameters. In annotation, we pass the query parameter name which will be appended in the URL.
1.1. Single or multiple query parameters
Use as many @Query annotations as many parameters we want to send.
https:///api/users?page=2&per_page=10
@GET("/api/users") public Call getUsers(@Query("per_page") int pageSize, @Query("page") int currentPage);
Pass the value of parameters when invoking the actual API call.
1.2. Multiple query parameters with same name
Let’s suppose we want to send multiple parameters which all have same name e.g. userId . It’s very uncommon scenario – still this can help we come across this requirement.
https:///api/users?userId=1&userId=2&userId=3
On server, it will be recieved as userId = [1,2,3] .
@GET("/api/users") public Call getUsers(@Query("userId") List ids);
1.3. Encoded query parameter
@Query annotation takes an attribute i.e. encoded . It is of boolean type and takes either true or false.
It specifies whether the argument value to the annotated method parameter is already URL encoded or not. Based on it’s value, URL encoding is performed on passed value. If value is passes as already URL encoded, no default URL encoding takes place.
By default, passed values are converted to encoded string.
1.4. Optional query parameters
Depending on the API design, in above examples, query parameter might be optional. In case we don’t want to pass the parameter with the request, we should just pass null as the value.
Retrofit skips null parameters and ignores them while creating the request.
We cannot pass ‘null’ to primitive types. So it is always recommended to use wrapper classes as parameter types.
E.g. Call to service.getUsers(null, null) will result in ‘https://DOMAIN/api/users’ .
Path parameters in Retrofit 2 are denoted with @Path annotation. They also come before method parameters. They are named replacement in a URL path segment.
Path parameters may not be null .
Values passed in @Path annotations modified and made URL encoded before full API path resolution.
2.1. Simple path parameter
An example to use @Path parameters in Retrofit 2.
@GET("/api/users/") public Call getUser(@Path("id") Long id);
Calling above API with service.getUser(1) yields ‘/api/users/1’.
2.2. Encoded path parameter
@Path annotation takes an attribute i.e. encoded . It is of boolean type and takes either true or false.
It specifies whether the argument value to the annotated method parameter is already URL encoded or not. Based on it’s value, URL encoding is performed on passed value. If value is passes as already URL encoded, no default URL encoding takes place.
By default, passed path parameters are converted to encoded string.
2.2.1. encoded = true
@GET("/user/") Call getUserByName(@Path(value="name") String name); //OR - encoded is default 'true' @GET("/user/") Call getUserByName(@Path(value="name", encoded=true) String name);
service.getUserByName(«John+Doe») will be resolved to ‘/user/John%2BDoe’ .
2.2.2. encoded = false
@GET("/user/") Call getUserByName(@Path(value="name", encoded=false) String name);
service.getUserByName(«John+Doe») will be resolved to ‘/user/John+Doe’ .
In this Retrofit tutorial, we’ve seen how we can use single, multiple and optional query parameters. We also learned to use path parameters.
Drop me your questions in comments.
Use objects to pass multiple query parameters when making a request using Retrofit
There are multiple instances where there is a need to make an API call to the SUSI.AI server to send or fetch data. The Android client uses Retrofit to make this process easier and more convenient.
While making a GET or POST request, there are often multiple query parameters that need to sent along with the base url. Here is an example how this is done:
@GET("/cms/getSkillFeedback.json") Call fetchFeedback( @Query("model") String model, @Query("group") String group, @Query("language") String language, @Query("skill") String skill);
It can be seen that the list of params can be very long indeed. A long list of params would lead to more risks of incorrect key value pairs and typos.
This blog would talk about replacing such multiple params with objects. The entire process would be explained with the help of an example of the API call being made to the getSkillFeedback.json API.
Step – 1 : Replace multiple params with a query map.
@GET("/cms/getSkillFeedback.json") Call fetchFeedback(@QueryMap Map query);
Step – 2 : Make a data class to hold query param values.
data class FetchFeedbackQuery( val model: String, val group: String, val language: String, val skill: String )
Step – 3 : Instead of passing all different strings for different query params, pass an object of the data class. Hence, add the following code to the ISkillDetailsModel.kt interface.
. fun fetchFeedback(query: FetchFeedbackQuery, listener: OnFetchFeedbackFinishedListener) .
Step – 4 : Add a function in the singleton file (ClientBuilder.java) to get SUSI client. This method should return a call.
. public static Call fetchFeedbackCall(FetchFeedbackQuery queryObject) < MapqueryMap = new HashMap(); queryMap.put("model", queryObject.getModel()); queryMap.put("group", queryObject.getGroup()); queryMap.put("language", queryObject.getLanguage()); queryMap.put("skill", queryObject.getSkill()); //Similarly add other params that might be needed return susiService.fetchFeedback(queryMap); > .
Step – 5 : Send a request to the getSkillFeedback.json API by passing an object of FetchFeedbackQuery data class to the fetchFeedbackCall method of the ClientBuilder.java file which in turn would return a call to the aforementioned API.
. override fun fetchFeedback(query: FetchFeedbackQuery, listener: ISkillDetailsModel.OnFetchFeedbackFinishedListener)
No other major changes are needed except that instead of passing individual strings for each query param as params to different methods and creating maps at different places like in a view, create an object of FetchFeedbackQuery class and use it to pass data throughout the project. This ensures type safety. Also, data classes reduce the code length significantly and hence are more convenient to use in practice.
Resources
- Kotlin data classes
https://kotlinlang.org/docs/reference/data-classes.html - A blog on ‘Retrofiting on Android with Kotlin’
https://segunfamisa.com/posts/using-retrofit-on-android-with-kotlin - Link to the SUSI.AI Android repository
https://github.com/fossasia/susi_android