Creating the Messenger API service

It's time for us to create a service that performs the all-important job of communicating with the Messenger API we created in Chapter 4, Designing and Implementing the Messenger Backend with Spring Boot 2.0. We will be making use of Retrofit and Retrofit's RxJava adapter to create this service. Retrofit is a type-safe HTTP client for Android and Java built by Square Inc., and RxJava is an open source implementation of ReactiveX written in and for Java.

We added Retrofit to our Android project at the beginning of this chapter with the following line:

implementation "com.squareup.retrofit2:retrofit:2.3.0"

We also added Retrofit's RxJava adapter dependency to our module-level build.gradle script, as follows:

implementation "com.squareup.retrofit2:adapter-rxjava2:2.3.0"

The first step in creating a service with Retrofit is to define an interface that describes your HTTP API. Create a service package within your application source package and add the MessengerApiService interface, as follows:

package com.example.messenger.service

import com.example.messenger.data.remote.request.LoginRequestObject
import com.example.messenger.data.remote.request.MessageRequestObject
import com.example.messenger.data.remote.request.StatusUpdateRequestObject
import com.example.messenger.data.remote.request.UserRequestObject
import com.example.messenger.data.vo.*
import io.reactivex.Observable
import okhttp3.ResponseBody
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.*

interface MessengerApiService {

@POST("login")
@Headers("Content-Type: application/json")
fun login(@Body user: LoginRequestObject):
Observable<retrofit2.Response<ResponseBody>>

@POST("users/registrations")
fun createUser(@Body user: UserRequestObject): Observable<UserVO>

@GET("users")
fun listUsers(@Header("Authorization") authorization: String):
Observable<UserListVO>

@PUT("users")
fun updateUserStatus(
@Body request: StatusUpdateRequestObject,
@Header("Authorization") authorization: String): Observable<UserVO>

@GET("users/{userId}")
fun showUser(
@Path("userId") userId: Long,
@Header("Authorization") authorization: String): Observable<UserVO>

@GET("users/details")
fun echoDetails(@Header("Authorization") authorization: String): Observable<UserVO>


@POST("messages")
fun createMessage(
@Body messageRequestObject: MessageRequestObject,
@Header("Authorization") authorization: String): Observable<MessageVO>

@GET("conversations")
fun listConversations(@Header("Authorization") authorization: String):
Observable<ConversationListVO>

@GET("conversations/{conversationId}")
fun showConversation(
@Path("conversationId") conversationId: Long,
@Header("Authorization") authorization: String):Observable<ConversationVO>
}

As can be observed from the preceding code snippet, Retrofit relies on the use of annotations to properly describe HTTP requests to be sent. Take the following snippet, for example:

@POST("login")
@Headers("Content-Type: application/json")
fun login(@Body user: LoginRequestObject): Observable<retrofit2.Response<ResponseBody>>

The @POST annotation tells Retrofit that this function describes an HTTP POST request that is mapped to the /login path. The @Headers annotation is used to specify the headers of the HTTP request. In the HTTP request described in the preceding code snippet, the Content-Type header has been set to application/json. Hence, the content being sent by this request is JSON.

The @Body annotation specifies that the user argument passed to login() contains the data of the JSON request body to be sent to the API. user is of the LoginRequestObject type (we previously created this request object). Lastly, the function is declared to return an Observable object containing a retrofit2.Response object.

Besides the @POST, @Headers, and @Body annotations, we made use of @GET, @PUT, @Path, and @Header. @GET and @PUT are used to specify GET and PUT requests, respectively. The @Path annotation is used to declare a value as a path argument of the HTTP request being sent. Take the following showUser() function, for example:

@GET("users/{userId}")
fun showUser(
@Path("userId") userId: Long,
@Header("Authorization") authorization: String): Observable<UserVO>

showUser is a function that describes a GET request with the users/{userId} path. {userId} is not actually part of the HTTP request path. Retrofit will replace {userId} with the value passed to the userId argument of showUser(). Notice how userId is annotated with @Path("userId"). This lets retrofit know that userId holds a value that should be placed where {userId} is located in the HTTP request URL path.

@Header is similar to @Headers, with the exception that it is used to specify a single header key-value pair in an HTTP request to be sent. Annotating authorization with @Header("Authorization") sets the Authorization header of the HTTP request sent to the value held within authorization.

Now that we have created an appropriate MessengerApiService interface to model the HTTP API that our application will communicate with, we need to be able to retrieve an instance of this service. We can easily do this by creating a Factory companion object that's in charge of the creation of MessengerApiService instances:

package com.example.messenger.service

import com.example.messenger.data.remote.request.LoginRequestObject
import com.example.messenger.data.remote.request.MessageRequestObject
import com.example.messenger.data.remote.request.StatusUpdateRequestObject
import com.example.messenger.data.remote.request.UserRequestObject
import com.example.messenger.data.vo.*
import io.reactivex.Observable
import okhttp3.ResponseBody
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.*

interface MessengerApiService {



companion object Factory {
private var service: MessengerApiService? = null

It returns an instance of MessengerApiService when invoked. A new instance of MessengerApiService is created, if one has not been previously created

   fun getInstance(): MessengerApiService {
if (service == null) {

val retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("{AWS_URL}")
// replace AWS_URL with URL of AWS EC2
// instance deployed in the previous chapter
.build()

service = retrofit.create(MessengerApiService::class.java)
}

return service as MessengerApiService
}
}
}

Factory possesses a single getInstance() function that builds and returns an instance of MessengerApiService when called. An instance of Retrofit.Builder is used to create the interface. We set  the CallAdapterFactory in use to RxJava2CallAdapterFactory and we set the ConverterFactory in use to GsonConverterFactory (this handles JSON serialization and deserialization). Don't forget to replace "{AWS_URL}" with the URL of the Messenger API AWS EC2 instance deployed in Chapter 4, Designing and Implementing the Messenger Backend with Spring Boot 2.0.

After creating the Retrofit.Builder() instance successfully, we use it to create an instance of MessengerApiService, as follows:

service = retrofit.create(MessengerApiService::class.java)

Lastly, the service is returned for use by getInstance(). Regardless of the fact that we have created a suitable service to communicate with the Messenger API, it cannot be used to communicate with a network without specifying the necessary permissions in the AndroidManifest. Open the project's AndroidManifest and add the following two lines of code within the <manifest></manifest> tag:

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

Now that we have the messenger service ready to go, it is time that we create appropriate repositories to exploit this service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.144.65