Android Networking: Fundamentals

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

Part 2: Implement Retrofit Basics

12. Implement a POST Call

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: 11. Build Retrofit Components Next episode: 13. Implement a GET Call

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: 12. Implement a POST Call

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

Transcript: 12. Implement a POST Call

Now that you’ve provided the Retrofit client and the api service, you can provide the API calls. To do this, you’ll need a few features and annotation classes from Retrofit.

Retrofit uses annotations for interface functions, to generate code which handles your requests. As such, by adding one of the REST method annotations, it knows how to generate the appropriate code, for the underlying HttpConnection.

By using Query, Header or Body annotations on function parameters, it knows which data to add to the request, and in what way. Let’s see how to implement one of the existing calls in Retrofit! :]

Open the RemoteApiService.kt, which you previously created. Add the following code:

@POST("/api/register")
fun registerUser(@Body request: RequestBody): Call<ResponseBody>

There are a few new concepts here.

@POST("/api/register")

First you have the POST annotation, which tells Retrofit this will be a POST request, to the following relative path. Remember how the relative endpoint path is everything after the BASE_URL.

@Body request: RequestBody

Then you have a request body, annotated with the Body annotation. Body tells retrofit to put this as the “body” parameter in the request. The RequestBody is a specific type in the OkHttp client, which describes data you can send to the server.

Call<ResponseBody>

Finally, you return a Call of the ResponseBody type. The ResponseBody is a counterpart to the RequestBody, where it describes data you receive.

The Call is a special Retrofit object, which describes a prepared API call, which you still need to start. This is everything you need from the api service side, to register a user! Now head over to the RemoteApi, and to the registerUser function. Remove the code, and add the following:

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

This snippet prepares the data, in the JSON format, as a RequestBody, for Retrofit. Then add the following, to enqueue the api call in the background:

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

apiService.registerUser(body).enqueue(object : Callback<ResponseBody> {
  override fun onFailure(call: Call<ResponseBody>, error: Throwable) {
    
  }

  override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
  }
})

Make sure to import the Retrofit version of the callback.

There are two ways of calling Retrofit api calls. Enqueue is the non-blocking, asynchronous way, where you get the result from the call in a Retrofit Callback.

Execute on the other hand is blocking, and will give you the result, but you have to handle your own threading and error handling with try/catch, which you want to avoid if possible.

Now fill in the onFailure and onSuccess callbacks like so:

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

apiService.registerUser(body).enqueue(object : Callback<ResponseBody> {
  override fun onFailure(call: Call<ResponseBody>, error: Throwable) {
    onUserCreated(null, error)
  }

  override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
    val message = response.body()?.string()
    if (message == null) {
      onUserCreated(null, NullPointerException("No response body!"))
      return
    }

    onUserCreated(message, null)
  }
})

The onFailure and onSuccess callbacks are used like their names state. onFailure is used for everything which fails the request. Things like lacking an Internet connection, trying to reach to an endpoint which doesn’t exist, or timing out.

The onSuccess case is used whenever any response comes back from the server. This does not necessarily mean a successful response, as you can still get an error response, saying you’re unauthorized, or that the server has an error. That’s still a response, albeit a negative one! :]

Responses can come in two forms. A positive response, with a non-null body, and a negative response, with a non-null errorBody. In this case, you’ll only check the body, and its value, and you won’t really care much about the error.

But in most applications, you can check the error message, and the error code, according to which you can determine what type of error happened, and then act accordingly.

Error codes range from the number 100, until 600, but not every number in between. Each “hundred” means a different range of messages.

  • 1xx codes are informational.
  • 2xx are positive, success codes.
  • 3xx are redirection codes.
  • 4xx are Client side errors, so things like unauthorized, bad data request or the famous “404: not found”.
  • 5xx are server side errors.

You’ll learn about specific errors as you work with applications, so you don’t need to know them all by heart!

That’s it from the RemoteApi side, now head over to the RegisterActivity.kt. Remove the runOnUiThread call, as you no longer need to post back to the main thread yourself!

runOnUiThread{}

Now run the project, and register another user! Log out of the app if you need first, by tapping the log out button on the profile tab.

Awesome! Everything still works like before, with a lot less code, and much cleaner syntax! And you don’t have to worry about threading, output or input streams of data, or the try/catch block for any crazy errors the API call might run into!