Last updated on: May 27, 2023
Retrofit is the most popular HTTP library and one of the most popular 3rd party libraries on Android.
Today, I’ll show you how to make the following HTTP requests using Retrofit:
- POST request with the most commonly used MIME types:
- application/json: Upload JSON data
- multipart/form-data: Upload files (images, texts e.t.c)
- application/x-www-form-urlencoded: Upload with the parameters encoded in the URL, for example
https://myrestapi.com/post?name=Jack&age=45
- GET request and how to use @Path and @Query
- PUT request
- DELETE request
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.
Contents
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.6.4'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Okhttp3 for the POST requests
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
// Gson to convert raw JSON to pretty JSON
implementation 'com.google.code.gson:gson:2.8.9'
// ...
}
Code language: Kotlin (kotlin)
at the same file, at the bottom of the android section, add:
android {
// ...
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
}
Code language: Kotlin (kotlin)
Adding Permissions & Preparing the Files
Go to the AndroidManifest.xml file and add the following permission:
<uses-permission android:name="android.permission.INTERNET" />
Code language: HTML, XML (xml)
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 the 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, etc.). 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 parameters 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>
// ...
}
Code language: Kotlin (kotlin)
Then, to create the JSON we’ll use the JSONObject() class and add the data we want to upload.
So, in 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())
}
}
}
}
Code language: Kotlin (kotlin)
• 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>
// ...
}
Code language: Kotlin (kotlin)
As you see, we’re using HashMap to add the data (string and .txt file), alongside 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())
}
}
}
}
Code language: Kotlin (kotlin)
• 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>
// ...
}
Code language: Kotlin (kotlin)
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())
}
}
}
}
Code language: Kotlin (kotlin)
Retrieving data using the 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>
// ...
}
Code language: Kotlin (kotlin)
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())
}
}
}
}
Code language: Kotlin (kotlin)
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>
// ...
}
Code language: Kotlin (kotlin)
Then, in your GET request, you can set the user id like that:
val response = service.getEmployee("53")
Code language: Kotlin (kotlin)
@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>
// ...
}
Code language: Kotlin (kotlin)
And in your GET request, set the page like this:
val response = service.getEmployees("2") // We're getting a list of users from the page 2
Code language: Kotlin (kotlin)
Updating data using the 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>
// ...
}
Code language: Kotlin (kotlin)
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())
}
}
}
}
Code language: Kotlin (kotlin)
Removing data using the 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>
// ...
}
Code language: Kotlin (kotlin)
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())
}
}
}
}
Code language: Kotlin (kotlin)
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 questions, please feel free to leave a comment below