Android Networking: Fundamentals

Sep 6 2022 · Kotlin 1.6, Android 12, Android Studio Chipmunk | 2021.2.1 Patch 1

Part 2: Implement Retrofit Basics

15. Add Queries to Calls

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 14. Challenge: Create Retrofit Calls Next episode: 16. Implement the Moshi Parser

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 15. Add Queries to Calls

The student materials have been reviewed and are updated as of July 2022.

Transcript: 15. Add Queries to Calls

Up until now, you only sent data as the body parameter, when you had a whole object to send. But sometimes, you don’t need entire objects, you just need to filter or search by one or two parameters. In that case, you often use queries.

Queries are specific search terms, which you append to the endpoint path, for the server to use and filter out exactly the specifics you are looking for. These queries start with a question mark, and then proceed to be in the format paramName=value.

For example, if you were to search the term “coroutines” on our website, you’d get something similar to this, of course, with the raywenderlich.com base url.

Here you can see that the search term query parameter is named “q”, and that there is another parameter named sort_order, which is equal to “relevance”.

This is useful, because if you were to create an endpoint for every single possible term and combination of queries there is, you’d have infinite endpoints to write, which is impossible to accomplish.

For this reason, it’s easier to just appent the search query to an existing endpoint, in case you want to make the request even more specific. Let’s see how to do that!

First, head over to RemoteApiService.kt, and add the following code:

@POST("/api/note/complete")
fun completeTask(
    @Header("Authorization") token: String,
    @Query("id") noteId: String): Call<ResponseBody>

@POST("/api/note")
fun addTask(
    @Header("Authorization") token: String,
    @Body request: RequestBody): Call<ResponseBody>

Here, you’re adding the completeTask endpoint, with the query parameter for the task id, and the addTask call, which you’ll re-implement using retrofit later on. Next, create a new class called CompleteNoteResponse, in the model/response package. Then add the following code:

class CompleteNoteResponse(val message: String?)

You’ll use this to parse the response from the server. Now move back to the RemoteApi, specifically the completeTask function. Add the following code:

apiService.completeTask(App.getToken(), taskId).enqueue(object : Callback<ResponseBody> {
  override fun onFailure(call: Call<ResponseBody>, error: Throwable) {
    onTaskCompleted(error)
  }

  override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
    val jsonBody = response.body()?.string()

    if (jsonBody == null) {
      onTaskCompleted(NullPointerException("No response!"))
      return
    }

    val completeNoteResponse = gson.fromJson(jsonBody, CompleteNoteResponse::class.java)
    if (completeNoteResponse?.message == null) {
      onTaskCompleted(NullPointerException("No response!"))
    } else {
      onTaskCompleted(null)
    }
  }
})

You already know most of the code here, and what it does, because it’s just the way each Retrofit call is implemented. The important thing is that you’re passing in the taskId as the query parameter, that will be formatted in the endpoint path. Now head over to the addTask function, and replace the code with the following:

val body = RequestBody.create(
    MediaType.parse("application/json"), gson.toJson(addTaskRequest)
)

apiService.addTask(App.getToken(), body).enqueue(object : Callback<ResponseBody> {
  override fun onFailure(call: Call<ResponseBody>, error: Throwable) {
    onTaskCreated(null, error)
  }

  override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
    val jsonBody = response.body()?.string()

    if (jsonBody == null) {
      onTaskCreated(null, NullPointerException("No response!"))
      return
    }

    val data = gson.fromJson(jsonBody, Task::class.java)

    if (data == null) {
      onTaskCreated(null, NullPointerException("No response!"))
      return
    } else {
      onTaskCreated(data, null)
    }
  }
})

Once again, you’re using the standard structure of an API call in Retrofit. You’re preparing the data in JSON, and sending it as body. Then you’re attaching a callback, and handling both the failure and success cases.

Now remove the runOnUiThread from the AddTaskDialogFragment and TaskOptionsDialogFragment.

Finally, run the project, and add a new note. Then complete that note, by long tapping it and selecting complete note.

Good job! Almost all API calls are now implemented in Retrofit! :] You can now proceed to implement a new, easier way of parsing data!