Overview
The NasaRepository class serves as an intermediary layer between the API service and the UI. It encapsulates business logic, manages API key handling, and transforms API responses into domain models.
Architecture Pattern
This repository follows the Repository Pattern, which abstracts data sources and provides a clean API for data access to the rest of the application.
Implementation
package com.ccandeladev.nasaexplorer.data.api
import com.ccandeladev.nasaexplorer.BuildConfig
import com.ccandeladev.nasaexplorer.domain.NasaModel
import javax.inject.Inject
class NasaRepository @Inject constructor(
private val nasaApiService: NasaApiService
) {
companion object {
private const val API_KEY = BuildConfig.NASA_API_KEY
}
suspend fun getImageOfTheDay(date: String? = null): NasaModel {
val response = nasaApiService.getImageOfTheDay(
apiKey = API_KEY,
date = date
)
return response.toNasaModel()
}
suspend fun getImagesInRange(
startDate: String,
endDate: String? = null
): List<NasaModel> {
val response = nasaApiService.getImagesInRange(
apiKey = API_KEY,
startDate = startDate,
endDate = endDate
)
return response.map { it.toNasaModel() }
}
suspend fun getRandomImages(count: Int): List<NasaModel> {
val response = nasaApiService.getRandomImages(
apiKey = API_KEY,
count = count
)
return response.map { it.toNasaModel() }
}
}
Dependency Injection
The repository is injected using Hilt/Dagger:
Retrofit service interface injected through constructor
@Inject
constructor(private val nasaApiService: NasaApiService)
API Key Management
The NASA API key is securely stored in BuildConfig and accessed as a constant:
companion object {
private const val API_KEY = BuildConfig.NASA_API_KEY
}
Never hardcode API keys in your repository. Always use BuildConfig or secure storage mechanisms.
Repository Methods
Get Image of the Day
Retrieves a single astronomy image for a specific date or today.
Date in YYYY-MM-DD format. Defaults to today if not provided
Domain model containing title, URL, date, and explanation
Usage in ViewModel:
viewModelScope.launch {
try {
val image = repository.getImageOfTheDay()
_uiState.value = UiState.Success(image)
} catch (e: Exception) {
_uiState.value = UiState.Error(e.message)
}
}
Get Images in Range
Fetches multiple images within a date range.
Start date in YYYY-MM-DD format
End date in YYYY-MM-DD format. Defaults to current date if not provided
List of domain models for each day in the range
Usage in ViewModel:
viewModelScope.launch {
try {
val images = repository.getImagesInRange(
startDate = "2024-01-01",
endDate = "2024-01-31"
)
_imageList.value = images
} catch (e: Exception) {
_error.value = e.message
}
}
Get Random Images
Retrieves a specified number of random astronomy images.
Number of random images to fetch (recommended: 1-100)
List of random domain models
Usage in ViewModel:
viewModelScope.launch {
try {
val randomImages = repository.getRandomImages(count = 10)
_randomList.value = randomImages
} catch (e: Exception) {
_error.value = e.message
}
}
The repository automatically converts API responses to domain models using the toNasaModel() extension function:
val response = nasaApiService.getImageOfTheDay(apiKey = API_KEY, date = date)
return response.toNasaModel()
This transformation decouples the data layer from the UI layer, allowing API changes without affecting the rest of the application.
Error Handling
All repository methods are suspend functions that propagate exceptions. Handle errors in the calling layer (typically ViewModels):
try {
val result = repository.getImageOfTheDay()
// Handle success
} catch (e: IOException) {
// Network error
} catch (e: HttpException) {
// API error
} catch (e: Exception) {
// Generic error
}
Testing
Mock the repository in your tests:
class FakeNasaRepository : NasaRepository {
override suspend fun getImageOfTheDay(date: String?): NasaModel {
return NasaModel(
title = "Test Image",
url = "https://example.com/image.jpg",
date = "2024-01-01",
explanation = "Test explanation"
)
}
}