Skip to content

Data Result Modeling Between Layers

Jung SeokJoon edited this page Mar 2, 2024 · 8 revisions

Introduction

GoonersApp is composed of several modules and has adopted some clean architecture.

The Network, Database, and Data modules are the Data layer, the Domain module is the Domain layer, and the feature module is the Presentation layer.

This article summarizes the modeling (mapping) that occurs when exchanging data between each layer and module.

Network To Data

This section is based on the following links : https://proandroiddev.com/modeling-retrofit-responses-with-sealed-classes-and-coroutines-9d6302077dfe

The Network module passes the API response received by Retrofit to the Data module.

Create a NetworkResult Sealed Class and convert the exception that occurs when calling the API and the value or error received in the response to a NetworkResult.

sealed class NetworkResult<T> {
    class Success<T>(val data: T) : NetworkResult<T>()
    class Error<T>(val code: Int, val message: String?) : NetworkResult<T>()
    class Exception<T>(val e: Throwable) : NetworkResult<T>()
}

According to our server API specification, the json data received in the response is contained in a key value called 'result'.

@Serializable
data class BaseResponse<T>(
    val result : T,
    /// Maybe 'code' or some other key-value will be added.
)

Therefore, we add the BaseResponse class and convert it to the type of data we actually want in handleApi.

suspend fun <T : Any> handleApi(
    execute: suspend () -> Response<BaseResponse<T>>
): NetworkResult<T> {
    return try {
        val response = execute()
        val body = response.body()
        if (response.isSuccessful && body != null) {
            NetworkResult.Success(body.result)
        } else {
            NetworkResult.Error(code = response.code(), message = response.message())
        }
    } catch (e: HttpException) {
        NetworkResult.Error(code = e.code(), message = e.message())
    } catch (e: Throwable) {
        NetworkResult.Exception(e)
    }
}

Through handleApi, we can receive NetworkResult in the form of Success, Error, and Exception and send it from DataSource(Network Module) to Data Module.

const val TEAM_BASE_URL = "/apis/team"

interface TeamNetworkService {

    @GET(value = "$TEAM_BASE_URL/detail")
    suspend fun getTeamDetail(
        @Query("teamId") teamId : Int
    ) : Response<BaseResponse<RemoteTeamDetail>>

}
class TeamNetworkDataSourceImpl @Inject constructor(
    private val teamNetworkService: TeamNetworkService
) : TeamNetworkDataSource {
    override suspend fun getTeamDetail(): NetworkResult<RemoteTeamDetail> {
        return handleApi {
            teamNetworkService.getTeamDetail()
        }
    }
}
Clone this wiki locally