Major code refactoring

Main goals are:
1. Ability to use mocks in unit tests instead of
having to setup mock web server as if it was an
integration test.
2. Cache Retrofit services in memory
3. Make it easier to read
4. Use OptIn where possible instead of propagating
Experimental* annotations everywhere
This commit is contained in:
Kirill Kamakin
2022-04-02 19:04:44 +05:00
parent 405d983a90
commit 7fc2887dc7
40 changed files with 533 additions and 676 deletions

View File

@@ -12,7 +12,7 @@ import kotlinx.coroutines.CancellationException
import timber.log.Timber
import javax.inject.Inject
@ExperimentalPagingApi
@OptIn(ExperimentalPagingApi::class)
class RecipeRepoImpl @Inject constructor(
private val mediator: RecipesRemoteMediator,
private val storage: RecipeStorage,

View File

@@ -11,7 +11,7 @@ import kotlinx.coroutines.CancellationException
import timber.log.Timber
import javax.inject.Inject
@ExperimentalPagingApi
@OptIn(ExperimentalPagingApi::class)
class RecipesRemoteMediator @Inject constructor(
private val storage: RecipeStorage,
private val network: RecipeDataSource,

View File

@@ -1,50 +1,35 @@
package gq.kirmanak.mealient.data.recipes.network
import gq.kirmanak.mealient.data.auth.AuthRepo
import gq.kirmanak.mealient.data.impl.RetrofitBuilder
import gq.kirmanak.mealient.data.network.ServiceFactory
import gq.kirmanak.mealient.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealient.data.recipes.network.response.GetRecipeSummaryResponse
import kotlinx.serialization.ExperimentalSerializationApi
import timber.log.Timber
import javax.inject.Inject
@ExperimentalSerializationApi
class RecipeDataSourceImpl @Inject constructor(
private val authRepo: AuthRepo,
private val retrofitBuilder: RetrofitBuilder
private val recipeServiceFactory: ServiceFactory<RecipeService>,
) : RecipeDataSource {
private var _recipeService: RecipeService? = null
override suspend fun requestRecipes(start: Int, limit: Int): List<GetRecipeSummaryResponse> {
Timber.v("requestRecipes() called with: start = $start, limit = $limit")
val service: RecipeService = getRecipeService()
val recipeSummary = service.getRecipeSummary(start, limit)
val recipeSummary = getRecipeService().getRecipeSummary(start, limit, getToken())
Timber.v("requestRecipes() returned: $recipeSummary")
return recipeSummary
}
override suspend fun requestRecipeInfo(slug: String): GetRecipeResponse {
Timber.v("requestRecipeInfo() called with: slug = $slug")
val service: RecipeService = getRecipeService()
val recipeInfo = service.getRecipe(slug)
val recipeInfo = getRecipeService().getRecipe(slug, getToken())
Timber.v("requestRecipeInfo() returned: $recipeInfo")
return recipeInfo
}
private suspend fun getRecipeService(): RecipeService {
Timber.v("getRecipeService() called")
val cachedService: RecipeService? = _recipeService
val service: RecipeService = if (cachedService == null) {
val baseUrl = checkNotNull(authRepo.getBaseUrl()) { "Base url is null" }
val token = checkNotNull(authRepo.getToken()) { "Token is null" }
Timber.d("requestRecipes: baseUrl = $baseUrl, token = $token")
val retrofit = retrofitBuilder.buildRetrofit(baseUrl)
val createdService = retrofit.create(RecipeService::class.java)
_recipeService = createdService
createdService
} else {
cachedService
}
return service
return recipeServiceFactory.provideService(authRepo.requireBaseUrl())
}
}
private suspend fun getToken(): String = authRepo.requireAuthHeader()
}

View File

@@ -3,6 +3,7 @@ package gq.kirmanak.mealient.data.recipes.network
import gq.kirmanak.mealient.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealient.data.recipes.network.response.GetRecipeSummaryResponse
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Path
import retrofit2.http.Query
@@ -10,11 +11,13 @@ interface RecipeService {
@GET("/api/recipes/summary")
suspend fun getRecipeSummary(
@Query("start") start: Int,
@Query("limit") limit: Int
@Query("limit") limit: Int,
@Header("Authorization") authHeader: String?,
): List<GetRecipeSummaryResponse>
@GET("/api/recipes/{recipe_slug}")
suspend fun getRecipe(
@Path("recipe_slug") recipeSlug: String
@Path("recipe_slug") recipeSlug: String,
@Header("Authorization") authHeader: String?,
): GetRecipeResponse
}