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