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<GetSkillFeedbackResponse> 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<GetSkillFeedbackResponse> fetchFeedback(@QueryMap Map<String, String> 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<GetSkillFeedbackResponse> fetchFeedbackCall(FetchFeedbackQuery queryObject){ Map<String, String> queryMap = new HashMap<String, String>(); 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) { fetchFeedbackResponseCall = ClientBuilder.fetchFeedbackCall(query) ... }
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