Consume RESTful API with Kotlin

Learn how to consume an API Rest with Kotlin, Sealed Class and Volley dependence

To have a general idea of Sealed Class I leave an explanation in the following link:

Now, let’s start

In first instance, we must keep in mind that the consumption a web services we can perform with the some other library (Retrofit, AndroidNetworking or other), but in this case we implement Volley.

Copy following code into build.gradle at app level
implementation 'com.android.volley:volley:1.1.0'

Volley is an HTTP library that makes networking for Android apps easier. Volley is available on GitHub.

And then, add necessary permissions to Android Manifest:
<uses-permission android:name="android.permission.INTERNET" />

To have order in the creation of the necessary classes, we will add the following files:

Example from package and clases
  • ApiRoute: this is own “Sealed class”, in this file we’ll add the route to consume, time-out, headers, their services specified in classes with parameters (if they are required), parameters to return and Volley connection.
  • ApiClient: here we’ll add the functions that will make the interaction between the route to be consumed and the response to return.
  • ApiResponse: this is a simply class that will process the response received from the service.
  • ApiResponseManager: this is optional to add, since in this we’ll do the real processing of the data that we’ll receive, such as user data or a list of objects, in this part we can add to our local database or return them directly.

Ready, for now we have everything we need to start with the interesting, the code.

ApiRoute

This is the first step to create our own Enum with steroids, but for now without structure, only configuration variables.

Both “params” and “headers” are optional and their creation depends directly on the API to consume.

Up to this point, we can not see the real power of this kind of class, since this is initial configuration.

But… then we’ll add the classes that make a “Sealed class

// Example: [object|class|data class] TypeName(): NameSealedClass()
/*
* For our case, we use the following types
*/
data class Login(var email: String, var password: String, var ctx: Context) : ApiRoute()
data class GetUser(var ctx: Context) : ApiRoute()
data class GetFeature(var householdID: Int, var ctx: Context) : ApiRoute()

As stated at the beginning of the article, a Sealed class is an Enum Type on steroids, but for the “types” to be recognized as such, it has to extend from its same container class and can be object, class or data class.

As we can see, Login, GetUser and GetFeature are data class since some parameters are needed to process, call or save the response.

Once we have declared our “types”, we can now complete our configuration variables. Like this:

This is how we finish the ApiRoute class in this example and continue with the other classes.


Before proceeding, we‘ll create our models for User and Features (or the models that we need depending on the project)

class User {

var id: Int = -1
var name: String = ""
var email: String = ""
var gender: String = ""
var age: Int = 0

companion object {
fun create(json: JSONObject): User {
val u = User()
try {
u.id = json.getInt("id")
u.name = json.getString("name")
u.email = json.getString("email")
u.gender = json.getString("gender")
u.age = json.getInt("age")
} catch (e: Exception) {
e.printStackTrace()
}
return u
}
}
}
class Feature {

var id: Int = -1
var name: String = ""
var icon: String = ""

companion object {
fun create(json: JSONObject): Feature {
val f = Feature()
try {
f.id = json.getInt("feature_id")
f.name = json.getString("name")
f.icon = json.getString("icon")
} catch (e: Exception) {
e.printStackTrace()
}
return f
}
}
}

These are the models that we will need as an example…

ApiResponse

As already mentioned, this class will help us to process the answer in a simple way, and the structure is like this:

Keeping in mind that the structure can change between projects, but the essence is the same.

For our example, all services respond with the following JSON structure:

{
"data":,
"error":
}
  • “data”: If the response of the HTTP request is successful (200), then it will contain an object or a list of objects, which we will later process.
  • “error”: this section will only appear if the HTTP request is not successful and will contain the message from the BackEnd that we will show to the user.

Now, our class would be as follows:

  • ApiResponse: her constructor receives as a parameter a String, and this is the answer that we get from the HTTP query made with Volley, we will see this part later.
  • success: with this variable we will know if we can continue with the process. And we will give you its value if we can create the object with “data”.
  • message: this variable will contain the message that will be shown to the user.
  • json: this is the response made by JSON, this is the object that we will handle later.
Now, our class is ready and we’ll continue with the next class to use ApiRoute and ApiResponse.

ApiClient

ApiClient will be our class that will interact with HTTP requests… As is…

Her “skeleton” is simple, but in the first instance we’ll create her constructor and the main functions for the query to the server.

Each method performs a specific task and this is our basis for making queries to the server.

If we remember a bit, previously in ApiRoute we created 3 data class: Login, GetUser and GetFeature, and these receive parameters, with this we‘ll add the necessary methods to perform a specific query, helping us with ApiRoute as follows:

  • The first method that we’ll add will be Login:

We receive as parameters the following:

  • email and password: These are the ones that request the service of our example.
  • completion: This is a return form that may or may not contain parameters to return, and this helps us because the calls to the server are done in the background and we can call it at the moment the query is over, and is created as follows: nameToUse: (“parameters to return or empty”) -> Unit. And to make the return of the object we do it in the following way: nameToUse.invoke(“Here you put the data to return”).
Practically this is the structure of all the methods we’ll use, but each one may or may not have parameters, but they always have to contain an escape method.

As we can see, this whole process is very easy and its implementation is even simpler.

Finally we’ll make the query and it would be as follows:

That’s it, it’s very simple and it does not take much to understand what we’ve done.

Do you think you can perform the other GetUser and GetFeature queries as an example? The models are now ready, all you need to do is create the function in ApiClient and send it to call.