Blog Infos
Author
Published
Topics
,
Published
sealed class Result<T> {
data class Success<T>(val data: T) : Result<T>()
data class Error<T>(val error: SomeErrorType) : Result<T>()
}
view raw Result.kt hosted with ❤ by GitHub
class GetMagicCardUseCase(
private val magicCardsRepository: MagicTheGatheringCardsRepository
) {
suspend operator fun invoke(cardName: String) : Result<MagicCard> {
if (!isCardNameValid(cardName)) {
return Error(InvalidCardNameFormat())
}
//...
return magicCardsRepository.getCard(cardName)
}
}

And then in the ViewModel:

class MagicCardSearchViewModel(
private val getCardUseCase: GetMagicCardUseCase
): ViewModel() {
fun onCardSearchClick() = viewModelScope.launch {
when (val result = getCardUseCase(cardName)) {
is Success -> // happy path 🎉
is Error -> {
result.error // 🤔
}
}
}
}
sealed class Result<out S, out E> {
data class Success<out S>(val data: S) : Result<S, Nothing>()
data class Error<out E>(val error: E) : Result<Nothing, E>()
}
class GetMagicCardUseCase(
private val mtgApi : MagicTheGatheringApi
) {
suspend operator fun invoke(cardName: String) : Result<MagicCard, GetMagicCardUseCaseError> {
if (!isCardNameValid(cardName)) {
return Error(InvalidCardNameFormat)
}
return try {
Success(mtgApi.getCard(cardName))
} catch (t: Throwable) {
val error = when (t) {
is IOException -> RemoteServerNotReachedError
is HttpException -> HttpUnsuccessfulCodeError(t.code())
else -> UnexpectedApiCommunicationError
}
return Error(error)
}
}
}
sealed class GetMagicCardUseCaseError
object InvalidCardNameFormat : GetMagicCardUseCaseError()
class HttpUnsuccessfulCodeError(val httpCode: Int) : GetMagicCardUseCaseError()
object RemoteServerNotReachedError : GetMagicCardUseCaseError()
object UnexpectedApiCommunicationError : GetMagicCardUseCaseError()
Enter — Sealed interfaces for the rescue 🙌
sealed interface GetMagicCardUseCaseError
object InvalidCardNameFormat : GetMagicCardUseCaseError
// -----------
sealed interface SaveNewDeckUseCaseError
object InvalidDeckSize : SaveNewDeckUseCaseError
// -----------
sealed interface ApiCallError : GetMagicCardUseCaseError, SaveNewDeckUseCaseError
class HttpUnsuccessfulCodeError(val httpCode: Int) : ApiCallError
object RemoteServerNotReachedError : ApiCallError
object UnexpectedApiCommunicationError : ApiCallError
sealed class GetMagicCardUseCaseError {
object InvalidCardNameFormat : GetMagicCardUseCaseError()
sealed class ApiCallError : GetMagicCardUseCaseError() {
class HttpUnsuccessfulCodeError(val httpCode: Int) : ApiCallError()
object RemoteServerNotReachedError : ApiCallError()
object UnexpectedApiCommunicationError : ApiCallError()
}
}
// Then handling one error would mean:
fun handleGetMagicCardUseCaseError(error: GetMagicCardUseCaseError) {
when (error) {
is GetMagicCardUseCaseError.ApiCallError.HttpUnsuccessfulCodeError -> //TODO
is GetMagicCardUseCaseError.ApiCallError.RemoteServerNotReachedError -> //TODO
is GetMagicCardUseCaseError.ApiCallError.UnexpectedApiCommunicationError -> //TODO
is GetMagicCardUseCaseError.InvalidCardNameFormat -> //TODO
}
}
sealed interface GetMagicCardUseCaseError
object InvalidCardNameFormat : GetMagicCardUseCaseError
sealed interface ApiCallError : GetMagicCardUseCaseError
class HttpUnsuccessfulCodeError(val httpCode: Int) : ApiCallError
object RemoteServerNotReachedError : ApiCallError
object UnexpectedApiCommunicationError : ApiCallError
fun handleError(error: GetMagicCardUseCaseError) {
when (error) {
is HttpUnsuccessfulCodeError -> //TODO
is RemoteServerNotReachedError -> //TODO
is UnexpectedApiCommunicationError -> //TODO
is InvalidCardNameFormat -> //TODO
}
}

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

Jobs

Hierarchy window on Android Studio IDE (ctrl +H on macOS while selecting one of the classes)
class PostNewDeckUseCase(
private val decksRepository: DecksRepository
) {
suspend operator fun invoke(newDeck: Deck) : Result<Unit, PostNewDeckUseCaseError> {
if (newDeck.cards.size != 60) {
return Failure(InvalidDeckSizeError)
}
//...
return decksRepository.createNewDeck(newDeck)
}
}
class DecksRepository(
private val someMagicTheGatheringApi : MagicTheGatheringApi
) {
suspend fun createNewDeck(newDeck : Deck) : Result<Unit, CreateNewDeckError> = withContect(Dispatchers.IO) {
someMagicTheGatheringApi.postNewDeck(newDeck.mapToDto())
//catch api exceptions and map them to `MagicTheGatheringApiCallError`
}
}
sealed interface PostNewDeckUseCaseError
object InvalidDeckSizeError: PostNewDeckUseCaseError
sealed interface CreateNewDeckError: PostNewDeckUseCaseError
object DeckAlreadyExistsError : CreateNewDeckError
sealed interface ApiCallError : GetSomethingUseCaseError, UpdateSomethingUseCaseError, CreateNewDeckError
//...
Conclusion
class GetMagicCardUseCase(
private val magicCardsRepository: MagicTheGatheringCardsRepository
) {
suspend operator fun invoke(cardName: String) : Result<MagicCard, GetMagicCardUseCaseError> {
if (!isCardNameValid(cardName)) {
return Error(InvalidCardNameFormat)
}
//...
return magicCardsRepository.getCard(cardName)
}
}

Considering the repository error type is ApiCallError, then this error hierarchy would suffice for our Use Case.

sealed interface GetMagicCardUseCaseError
object InvalidCardNameFormat : GetMagicCardUseCaseError
sealed interface ApiCallError : GetMagicCardUseCaseError
class HttpUnsuccessfulCodeError(val httpCode: Int) : ApiCallError
object RemoteServerNotReachedError : ApiCallError
object UnexpectedApiCommunicationError : ApiCallError

And in the ViewModel:

class MagicCardSearchViewModel(
private val getCardUseCase: GetMagicCardUseCase
): ViewModel() {
fun onCardSearchClick() = viewModelScope.launch {
when (val result = getCardUseCase(cardName)) {
is Success -> // happy path 🎉
is Error -> onGetCardError(result.error)
}
}
private fun onGetCardError(error: GetMagicCardUseCaseError) {
when (error) {
is InvalidCardNameFormat -> //TODO
is HttpUnsuccessfulCodeError -> //TODO
is RemoteServerNotReachedError -> //TODO
is UnexpectedApiCommunicationError -> //TODO
}
}
}

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu