fbpx
How to make POST, GET, PUT and DELETE requests with Retrofit using Kotlin

How to make POST, GET, PUT and DELETE requests with Retrofit using Kotlin

Retrofit is the most popular HTTP library and one of the most popular 3rd party libraries on Android.

Today, I’ll to show you how to do the following HTTP requests using Retrofit:

Retrofit not only can make HTTP requests but can also parse the JSON simultaneously.

I’m NOT going to show you how to parse the JSON data in this tutorial, but only how to make HTTP requests and print the results.

If you want to parse JSON with Retrofit, you need to read the current article first and then follow this.

Adding the libraries

Go to your app-level build.gradle file and add the following dependencies:

// ...

dependencies {
    // ...

    // Coroutines to make the HTTP requests asynchronous(In the background thread)
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'

    // Okhttp3 for the POST requests
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'

    // Gson (To convert raw JSON to pretty JSON)
    implementation 'com.google.code.gson:gson:2.8.6'

    // ...
}

at the same file, at the bottom of the android section, add:

android {

    // ...

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

Adding Permissions & Preparing the Files

Go to the AndroidManifest.xml file and add the following permission:

<uses-permission android:name="android.permission.INTERNET" />

Now, create a new Kotlin Interface file to put our @POST, @GET, @PUT, and @DELETE annotations later.

Right-click on your project name > New > Kotlin File/Class

Select Interface, name the file APIService and press Enter

After that, the file will look like this:

Adding data using POST method

To add data to the server, you need to use the HTTP request method POST.

Before you upload the data, you have to define what type of data you are uploading (e.g., raw JSON, media e.t.c). To do that, you need to set the MIME type.

  • application/json for raw JSON data
  • multipart/form-data for files, like images, pdfs, texts e.t.c
  • application/x-www-form-urlencoded for passing the paramers encoded in the URL

• Uploading JSON data (application/json)

In this example, we’re going to POST the following data as raw JSON data in the URL: http://dummy.restapiexample.com/api/v1/create

  • name: Jack
  • salary: 3540
  • age: 23

First, in the APIService.kt file add the following @POST annotation:

interface APIService {
    // ...

    @POST("/api/v1/create")
    suspend fun createEmployee(@Body requestBody: RequestBody): Response<ResponseBody>

    // ...
}

Then, to create the JSON we’ll use the JSONObject() class and add the data we want to upload.

So, at the end, the POST request will look like this:

fun rawJSON() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("http://dummy.restapiexample.com")
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    // Create JSON using JSONObject
    val jsonObject = JSONObject()
    jsonObject.put("name", "Jack")
    jsonObject.put("salary", "3540")
    jsonObject.put("age", "23")

    // Convert JSONObject to String
    val jsonObjectString = jsonObject.toString()

    // Create RequestBody ( We're not using any converter, like GsonConverter, MoshiConverter e.t.c, that's why we use RequestBody )
    val requestBody = jsonObjectString.toRequestBody("application/json".toMediaTypeOrNull())

    CoroutineScope(Dispatchers.IO).launch {
        // Do the POST request and get response
        val response = service.createEmployee(requestBody)

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                // Convert raw JSON to pretty JSON using GSON library
                val gson = GsonBuilder().setPrettyPrinting().create()
                val prettyJson = gson.toJson(
                    JsonParser.parseString(
                        response.body()
                            ?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
                    )
                )
                
                Log.d("Pretty Printed JSON :", prettyJson)

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}

• Uploading Files (multipart/form-data)

In this example, we’re going to POST a String value and a .txt file in the URL: https://httpbin.org/post

  • email: jack@email.com
  • file: lorem_ipsum.txt

First, in the APIService.kt file add:

interface APIService {
    // ...

    @Multipart
    @POST("/post")
    suspend fun uploadEmployeeData(@PartMap map: HashMap<String?, RequestBody?>): Response<ResponseBody>

    // ...
}

As you see, we’re using HashMap to add the data (string and .txt file), alongside with Retrofit’s @PartMap annotation

…and the POST request will be:

fun formData() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://httpbin.org")
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    // List of all MIME Types you can upload: https://www.freeformatter.com/mime-types-list.html

    // Get file from assets folder
    val file = getFileFromAssets(this, "lorem_ipsum.txt")

    val fields: HashMap<String?, RequestBody?> = HashMap()
    fields["email"] = ("jack@email.com").toRequestBody("text/plain".toMediaTypeOrNull())
    fields["file\"; filename=\"upload_file.txt\" "] =
        (file).asRequestBody("text/plain".toMediaTypeOrNull())

    CoroutineScope(Dispatchers.IO).launch {

        // Do the POST request and get response
        val response = service.uploadEmployeeData(fields)

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                // Convert raw JSON to pretty JSON using GSON library
                val gson = GsonBuilder().setPrettyPrinting().create()
                val prettyJson = gson.toJson(
                    JsonParser.parseString(
                        response.body()
                            ?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
                    )
                )

                Log.d("Pretty Printed JSON :", prettyJson)

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}

• Uploading with parameters encoded in the URL (application/x-www-form-urlencoded)

To have the parameters encoded in the URL, all you have to do is to add the @FormUrlEncoded annotation in the APIService.kt file and use HashMap with the @FieldMap annotation.

interface APIService {
    // ...

    @FormUrlEncoded
    @POST("/post")
    suspended fun createEmployee(@FieldMap params: HashMap<String?, String?>): Response<ResponseBody>

    // ...
}

And when you make the POST request, create a HashMap and add the parameters you want:

fun urlEncoded() {
    
    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://postman-echo.com")
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    // Create HashMap with fields
    val params = HashMap<String?, String?>()
    params["name"] = "Jack"
    params["salary"] = "8054"
    params["age"] = "45"

    CoroutineScope(Dispatchers.IO).launch {

        // Do the POST request and get response
        val response = service.createEmployee(params)

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                // Convert raw JSON to pretty JSON using GSON library
                val gson = GsonBuilder().setPrettyPrinting().create()
                val prettyJson = gson.toJson(
                    JsonParser.parseString(
                        response.body()
                            ?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
                    )
                )
                
                Log.d("Pretty Printed JSON :", prettyJson)

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}

Retrieving data using GET method

To retrieve the data from the server, you need to use the HTTP request method GET.

In this example, we’re going to get a list of employees from the URL: http://dummy.restapiexample.com/api/v1/employees

Go to the APIService.kt file, add the @GET annotation with the path of the URL:

interface APIService {
    // ...

    @GET("/api/v1/employees")
    suspend fun getEmployees(): Response<ResponseBody>

    // ...
}

And make the GET request:

fun getMethod() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("http://dummy.restapiexample.com")
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    CoroutineScope(Dispatchers.IO).launch {
        /*
         * For @Query: You need to replace the following line with val response = service.getEmployees(2)
         * For @Path: You need to replace the following line with val response = service.getEmployee(53)
         */

        // Do the GET request and get response
        val response = service.getEmployees()

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                // Convert raw JSON to pretty JSON using GSON library
                val gson = GsonBuilder().setPrettyPrinting().create()
                val prettyJson = gson.toJson(
                    JsonParser.parseString(
                        response.body()
                            ?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
                    )
                )
                
                Log.d("Pretty Printed JSON :", prettyJson)

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}

Using @Path and @Query

@Path

If you want to get the data of a specific user using their id, you can do it by using the @Path annotation:

interface APIService {
    // ...

    // Request using @Path (e.g https://reqres.in/api/user/53 - This URL is just an example, it's not working)
    @GET("/api/users/{Id}")
    suspend fun getEmployee(@Path("Id") employeeId: String): Response<ResponseBody>

    // ...
}

Then, in your GET request, you can set the user id like that:

val response = service.getEmployee("53")

@Query

Let’s say you have a URL that uses pagination to get the JSON data(e.g., https://reqres.in/api/users?page=2), you can change the number of the page by using the @Query("page") annotation.

So, in your APIService.kt file:

interface APIService {
    // ...

    // Request using @Query (e.g https://reqres.in/api/users?page=2)
    @GET("/api/users")
    suspend fun getEmployees(@Query("page") page: String?): Response<ResponseBody>

    // ...
}

And in your GET request, set the page like:

val response = service.getEmployees("2") // We're getting a list of users from the page 2

Updating data using PUT method

To update the data on the server, you need to use the HTTP request method PUT, which is almost the same as the POST method.

Go to your APIService.kt file and add the @PUT annotation with the path of the URL:

interface APIService {
    // ...

    @PUT("/api/users/2")
    suspend fun updateEmployee(@Body requestBody: RequestBody): Response<ResponseBody>

    // ...
}

Then, create a new PUT request:

fun putMethod() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://reqres.in")
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    // Create JSON using JSONObject
    val jsonObject = JSONObject()
    jsonObject.put("name", "Nicole")
    jsonObject.put("job", "iOS Developer")

    // Convert JSONObject to String
    val jsonObjectString = jsonObject.toString()

    // Create RequestBody ( We're not using any converter, like GsonConverter, MoshiConverter e.t.c, that's why we use RequestBody )
    val requestBody = jsonObjectString.toRequestBody("application/json".toMediaTypeOrNull())

    CoroutineScope(Dispatchers.IO).launch {

        // Do the PUT request and get response
        val response = service.updateEmployee(requestBody)

        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                // Convert raw JSON to pretty JSON using GSON library
                val gson = GsonBuilder().setPrettyPrinting().create()
                val prettyJson = gson.toJson(
                    JsonParser.parseString(
                        response.body()
                            ?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
                    )
                )
                
                Log.d("Pretty Printed JSON :", prettyJson)

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}

Removing data using DELETE method

To delete the data from the server, you need to use the HTTP request method DELETE.

In the APIService.kt file, add the @DELETE annotation with the path of the URL you want to delete:

interface APIService {
    // ...

    @DELETE("/typicode/demo/posts/1")
    suspend fun deleteEmployee(): Response<ResponseBody>

    // ...
}

And make a DELETE request:

fun deleteMethod() {

    // Create Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://my-json-server.typicode.com/")
        .build()

    // Create Service
    val service = retrofit.create(APIService::class.java)

    CoroutineScope(Dispatchers.IO).launch {

        // Do the DELETE request and get response

        val response = service.deleteEmployee()
        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {

                // Convert raw JSON to pretty JSON using GSON library
                val gson = GsonBuilder().setPrettyPrinting().create()
                val prettyJson = gson.toJson(
                    JsonParser.parseString(
                        response.body()
                            ?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
                    )
                )
                
                Log.d("Pretty Printed JSON :", prettyJson)

            } else {

                Log.e("RETROFIT_ERROR", response.code().toString())

            }
        }
    }
}

In this example, the URL I’m using for the DELETE method doesn’t return any response after deleting the item. That’s why the results are empty.

You can find the final project here

If you have any questionsplease feel free to leave a comment below

Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Rick

Hi, we found an error in your examples.
In the API you’re having this line:

@PUT("/api/users/2")
    suspend fun updateEmployee(@Body requestBody: RequestBody): Call<ResponseBody>

but it should be:

@PUT("/api/users/2")
    suspend fun updateEmployee(@Body requestBody: RequestBody): Response<ResponseBody>

as seen in your example project 🙂