Repository Interfaces
Repository interfaces define the contracts for data access operations in the domain layer. Following Clean Architecture principles, these interfaces reside in the domain layer while their implementations are in the data layer.
ProductRepository
Defines operations for obtaining product data from Mercado Libre.
Interface Definition
interface ProductRepository {
suspend fun searchProducts(query: String): Result<List<Product>>
suspend fun getProductDetail(id: String): Result<ProductDetail>
}
Methods
searchProducts
Performs a product search based on a query term.
suspend fun searchProducts(query: String): Result<List<Product>>
Search text to query active products
Result containing a list of Product models on success, or a mapped failure
Usage Example:
class GetProductsUseCase @Inject constructor(
private val repository: ProductRepository
) {
suspend operator fun invoke(query: String): Result<List<Product>> {
return repository.searchProducts(query)
}
}
// In a ViewModel or use case
val result = productRepository.searchProducts("laptop")
result.fold(
onSuccess = { products ->
println("Found ${products.size} products")
},
onFailure = { error ->
println("Search failed: ${error.message}")
}
)
getProductDetail
Retrieves complete details of a specific product by its identifier.
suspend fun getProductDetail(id: String): Result<ProductDetail>
Unique product identifier (e.g., “MCO12345”)
Result containing the ProductDetail model if found, or a failure otherwise
Usage Example:
class GetProductDetailUseCase @Inject constructor(
private val repository: ProductRepository
) {
suspend operator fun invoke(id: String): Result<ProductDetail> {
return repository.getProductDetail(id)
}
}
// In a ViewModel
viewModelScope.launch {
val result = productRepository.getProductDetail("MCO12345")
result.fold(
onSuccess = { detail ->
_uiState.value = UiState.Success(detail)
},
onFailure = { error ->
_uiState.value = UiState.Error(error.message)
}
)
}
TokenRepository
Contract for managing authentication tokens required for authorized API requests to Mercado Libre.
Interface Definition
interface TokenRepository {
fun getAccessToken(): String?
suspend fun refreshToken(): Result<String>
}
Methods
getAccessToken
Retrieves the currently stored access token.
fun getAccessToken(): String?
The access token as a String, or null if no token is available
Usage Example:
class AuthInterceptor @Inject constructor(
private val tokenRepository: TokenRepository
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val token = tokenRepository.getAccessToken()
val request = if (token != null) {
chain.request().newBuilder()
.addHeader("Authorization", "Bearer $token")
.build()
} else {
chain.request()
}
return chain.proceed(request)
}
}
refreshToken
Requests a renewal of the current access token.
suspend fun refreshToken(): Result<String>
Result containing the new access token on success, or an exception on error
Usage Example:
class TokenAuthenticator @Inject constructor(
private val tokenRepository: TokenRepository
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
return runBlocking {
val result = tokenRepository.refreshToken()
result.fold(
onSuccess = { newToken ->
response.request.newBuilder()
.header("Authorization", "Bearer $newToken")
.build()
},
onFailure = {
null // Authentication failed
}
)
}
}
}
Error Handling
Both repositories return Result<T> types, which can contain either a success value or a failure. Failures may include:
- Network errors: Connectivity issues
- Timeout errors: Request exceeded time limit
- Server errors: HTTP 4xx/5xx responses
- Unknown errors: Unexpected exceptions
Refer to the AppError sealed class for the complete error hierarchy:
sealed class AppError : Exception() {
class Network : AppError()
class Timeout : AppError()
data class Server(val code: Int, val msg: String) : AppError()
data class Unknown(val throwable: Throwable) : AppError()
}
Package Location
com.alcalist.tecmeli.domain.repository
Repository interfaces are located in the domain.repository package, while implementations reside in data.repository following Clean Architecture and Dependency Inversion principles.