Reuse OkHttp instance
This commit is contained in:
@@ -6,7 +6,6 @@ import androidx.room.TypeConverters
|
||||
import gq.kirmanak.mealient.data.impl.RoomTypeConverters
|
||||
import gq.kirmanak.mealient.data.recipes.db.RecipeDao
|
||||
import gq.kirmanak.mealient.data.recipes.db.entity.*
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Database(
|
||||
version = 1,
|
||||
@@ -14,7 +13,6 @@ import javax.inject.Singleton
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(RoomTypeConverters::class)
|
||||
@Singleton
|
||||
abstract class AppDb : RoomDatabase() {
|
||||
abstract fun recipeDao(): RecipeDao
|
||||
}
|
||||
@@ -9,19 +9,35 @@ import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import gq.kirmanak.mealient.data.impl.OkHttpBuilder
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.OkHttpClient
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface AppModule {
|
||||
companion object {
|
||||
@Provides
|
||||
fun createDb(@ApplicationContext context: Context): AppDb {
|
||||
return Room.databaseBuilder(context, AppDb::class.java, "app.db").build()
|
||||
}
|
||||
@Singleton
|
||||
fun createDb(@ApplicationContext context: Context): AppDb =
|
||||
Room.databaseBuilder(context, AppDb::class.java, "app.db").build()
|
||||
|
||||
@Provides
|
||||
fun createSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||
@Singleton
|
||||
fun createSharedPreferences(@ApplicationContext context: Context): SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun createOkHttp(okHttpBuilder: OkHttpBuilder): OkHttpClient =
|
||||
okHttpBuilder.buildOkHttp()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun createJson(): Json = Json {
|
||||
coerceInputValues = true
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,29 @@
|
||||
package gq.kirmanak.mealient.data.auth.impl
|
||||
|
||||
import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
const val AUTHORIZATION_HEADER = "Authorization"
|
||||
|
||||
class AuthOkHttpInterceptor(token: String) : Interceptor {
|
||||
private val headerValue = "Bearer $token"
|
||||
|
||||
class AuthOkHttpInterceptor @Inject constructor(
|
||||
private val authStorage: AuthStorage
|
||||
) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val newRequest = chain.request()
|
||||
.newBuilder()
|
||||
.addHeader(AUTHORIZATION_HEADER, headerValue)
|
||||
.build()
|
||||
return chain.proceed(newRequest)
|
||||
Timber.v("intercept() called with: chain = $chain")
|
||||
val token = runBlocking { authStorage.getToken() }
|
||||
Timber.d("intercept: token = $token")
|
||||
val request = if (token.isNullOrBlank()) {
|
||||
chain.request()
|
||||
} else {
|
||||
chain.request()
|
||||
.newBuilder()
|
||||
.addHeader(AUTHORIZATION_HEADER, "Bearer $token")
|
||||
.build()
|
||||
}
|
||||
return chain.proceed(request)
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,14 @@ import okhttp3.logging.HttpLoggingInterceptor
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class OkHttpBuilder @Inject constructor() {
|
||||
fun buildOkHttp(token: String?): OkHttpClient {
|
||||
Timber.v("buildOkHttp() called with: token = $token")
|
||||
class OkHttpBuilder @Inject constructor(
|
||||
private val authOkHttpInterceptor: AuthOkHttpInterceptor
|
||||
) {
|
||||
fun buildOkHttp(): OkHttpClient {
|
||||
Timber.v("buildOkHttp() called")
|
||||
val builder = OkHttpClient.Builder()
|
||||
if (BuildConfig.DEBUG) builder.addNetworkInterceptor(buildLoggingInterceptor())
|
||||
if (token != null) builder.addNetworkInterceptor(AuthOkHttpInterceptor(token))
|
||||
builder.addNetworkInterceptor(authOkHttpInterceptor)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,26 +4,23 @@ import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFact
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ExperimentalSerializationApi
|
||||
class RetrofitBuilder @Inject constructor(private val okHttpBuilder: OkHttpBuilder) {
|
||||
private val json by lazy {
|
||||
Json {
|
||||
coerceInputValues = true
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
}
|
||||
|
||||
fun buildRetrofit(baseUrl: String, token: String? = null): Retrofit {
|
||||
Timber.v("buildRetrofit() called with: baseUrl = $baseUrl, token = $token")
|
||||
class RetrofitBuilder @Inject constructor(
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val json: Json
|
||||
) {
|
||||
fun buildRetrofit(baseUrl: String): Retrofit {
|
||||
Timber.v("buildRetrofit() called with: baseUrl = $baseUrl")
|
||||
val contentType = "application/json".toMediaType()
|
||||
val converterFactory = json.asConverterFactory(contentType)
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.client(okHttpBuilder.buildOkHttp(token))
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(converterFactory)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class RecipeDataSourceImpl @Inject constructor(
|
||||
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, token)
|
||||
val retrofit = retrofitBuilder.buildRetrofit(baseUrl)
|
||||
val createdService = retrofit.create(RecipeService::class.java)
|
||||
_recipeService = createdService
|
||||
createdService
|
||||
|
||||
@@ -2,8 +2,10 @@ package gq.kirmanak.mealient.data.impl
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||
import gq.kirmanak.mealient.data.auth.impl.AUTHORIZATION_HEADER
|
||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_TOKEN
|
||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_URL
|
||||
import gq.kirmanak.mealient.test.MockServerTest
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
@@ -17,16 +19,20 @@ class OkHttpBuilderTest : MockServerTest() {
|
||||
@Inject
|
||||
lateinit var subject: OkHttpBuilder
|
||||
|
||||
@Inject
|
||||
lateinit var authStorage: AuthStorage
|
||||
|
||||
@Test
|
||||
fun `when token null then no auth header`() {
|
||||
val client = subject.buildOkHttp(null)
|
||||
val client = subject.buildOkHttp()
|
||||
val header = sendRequestAndExtractAuthHeader(client)
|
||||
assertThat(header).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when token isn't null then auth header contains token`() {
|
||||
val client = subject.buildOkHttp(TEST_TOKEN)
|
||||
authStorage.storeAuthData(TEST_TOKEN, TEST_URL)
|
||||
val client = subject.buildOkHttp()
|
||||
val header = sendRequestAndExtractAuthHeader(client)
|
||||
assertThat(header).isEqualTo("Bearer $TEST_TOKEN")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user