Skip to content

Commit

Permalink
Differentiate unathenticated errors from other errors in safeFlow()
Browse files Browse the repository at this point in the history
  • Loading branch information
StylianosGakis committed Nov 22, 2024
1 parent d37138f commit ab3a8bb
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,22 @@ sealed interface ApolloOperationError {
}
}

data class OperationError(private val message: String) : ApolloOperationError {
override val throwable: Throwable? = null
sealed interface OperationError : ApolloOperationError {
object Unathenticated : OperationError {
override val throwable: Throwable? = null

override fun toString(): String {
return "OperationError.Unathenticated"
}
}

data class Other(private val message: String) : OperationError {
override val throwable: Throwable? = null

override fun toString(): String {
return "OperationError.Other(message=$message)"
}
}
}
}

Expand Down Expand Up @@ -103,6 +117,17 @@ fun ErrorMessage(apolloOperationError: ApolloOperationError): ErrorMessage = obj
}
}

@JvmInline
value class ExtensionErrorType(val value: String) {
companion object {
val Unauthenticated = ExtensionErrorType("UNAUTHENTICATED")
}
}

fun Error.extensionErrorType(): ExtensionErrorType? {
return extensions?.get("errorType")?.let { ExtensionErrorType(it.toString()) }
}

// https://www.apollographql.com/docs/kotlin/essentials/errors/#truth-table
private fun <D : Operation.Data> IorRaise<Nel<ApolloOperationError>>.parseResponse(response: ApolloResponse<D>): D {
val exception = response.exception
Expand All @@ -129,14 +154,18 @@ private fun <D : Operation.Data> IorRaise<Nel<ApolloOperationError>>.parseRespon
private fun List<Error>?.mapToOperationErrors(): Nel<ApolloOperationError>? {
if (this == null) return null
return map { error ->
ApolloOperationError.OperationError(
buildString {
append(error.message)
if (error.extensions != null) {
append(error.extensions!!.toList().joinToString(prefix = " ext: [", postfix = "]", separator = ", "))
}
},
)
if (error.extensionErrorType() == ExtensionErrorType.Unauthenticated) {
ApolloOperationError.OperationError.Unathenticated
} else {
ApolloOperationError.OperationError.Other(
buildString {
append(error.message)
if (error.extensions != null) {
append(error.extensions!!.toList().joinToString(prefix = " ext: [", postfix = "]", separator = ", "))
}
},
)
}
}.toNonEmptyListOrNull()
}

Expand All @@ -145,7 +174,7 @@ private fun List<Error>?.mapToOperationErrors(): Nel<ApolloOperationError>? {
*/
private fun <D : Operation.Data> IorNel<ApolloOperationError, D>.iorToEither(): Either<ApolloOperationError, D> {
return mapLeft { errors ->
ApolloOperationError.OperationError(
ApolloOperationError.OperationError.Other(
errors.joinToString(prefix = " [", postfix = "]", separator = ", ") { it.toString() },
)
}.toEither()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.apollographql.apollo.api.Operation.Data
import com.apollographql.apollo.exception.CacheMissException
import com.apollographql.apollo.interceptor.ApolloInterceptor
import com.apollographql.apollo.interceptor.ApolloInterceptorChain
import com.hedvig.android.apollo.ExtensionErrorType
import com.hedvig.android.apollo.extensionErrorType
import com.hedvig.android.auth.AuthTokenService
import com.hedvig.android.core.tracking.ErrorSource
import com.hedvig.android.core.tracking.logError
Expand Down Expand Up @@ -103,20 +105,13 @@ private data class LoggableGraphqlError(
)

data class Extensions(
val errorType: ErrorType?,
val errorType: ExtensionErrorType?,
val uncategorizedExtensions: Map<String, Any?>?,
) {
@JvmInline
value class ErrorType(val value: String) {
companion object {
val Unauthenticated = ErrorType("UNAUTHENTICATED")
}
}
}
)
}

private fun List<LoggableGraphqlError>.isUnathenticated(): Boolean {
return any { it.extensions.errorType == LoggableGraphqlError.Extensions.ErrorType.Unauthenticated }
return any { it.extensions.errorType == ExtensionErrorType.Unauthenticated }
}

private fun ApolloKotlinError.toGraphqlError(): LoggableGraphqlError {
Expand All @@ -125,7 +120,7 @@ private fun ApolloKotlinError.toGraphqlError(): LoggableGraphqlError {
locations = this.locations?.map { LoggableGraphqlError.Location(it.line, it.column) },
paths = this.path?.map { LoggableGraphqlError.Path(it.toString()) },
extensions = LoggableGraphqlError.Extensions(
errorType = this.extensions?.get("errorType")?.let { LoggableGraphqlError.Extensions.ErrorType(it.toString()) },
errorType = this.extensionErrorType(),
uncategorizedExtensions = this.extensions?.minus("errorType"),
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class HasAnyActiveConversationUseCase(
either {
val data = result
.onLeft { apolloOperationError ->
if (apolloOperationError is ApolloOperationError.OperationError.Unathenticated) return@onLeft
logcat(LogPriority.ERROR, apolloOperationError.throwable) {
"isEligibleToShowTheChatIcon cant determine if the chat icon should be shown. $apolloOperationError"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ internal class HomePresenterTest {
assertThat(awaitItem()).isEqualTo(HomeUiState.Loading)
assertThat(getHomeDataUseCase.forceNetworkFetchTurbine.awaitItem()).isFalse()

getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError("").left())
getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError.Other("").left())
assertThat(awaitItem()).isInstanceOf<HomeUiState.Error>()

sendEvent(HomeEvent.RefreshData)
assertThat(getHomeDataUseCase.forceNetworkFetchTurbine.awaitItem()).isTrue()
assertThat(awaitItem()).isInstanceOf<HomeUiState.Loading>()

getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError("").left())
getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError.Other("").left())
assertThat(awaitItem()).isInstanceOf<HomeUiState.Error>()
}
}
Expand All @@ -72,7 +72,7 @@ internal class HomePresenterTest {
homePresenter.test(HomeUiState.Loading) {
assertThat(awaitItem()).isEqualTo(HomeUiState.Loading)

getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError("").left())
getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError.Other("").left())
assertThat(awaitItem()).isInstanceOf<HomeUiState.Error>()

sendEvent(HomeEvent.RefreshData)
Expand Down Expand Up @@ -208,7 +208,7 @@ internal class HomePresenterTest {
homePresenter.test(HomeUiState.Loading) {
assertThat(awaitItem()).isEqualTo(HomeUiState.Loading)

getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError("").left())
getHomeDataUseCase.responseTurbine.add(ApolloOperationError.OperationError.Other("").left())
assertThat(awaitItem()).isInstanceOf<HomeUiState.Error>()

getHomeDataUseCase.responseTurbine.add(someIrrelevantHomeDataInstance.right())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class EurobonusPresenterTest {
),
) {
awaitItem()
getEurobonusDataUseCase.responseTurbine.add(ApolloOperationError.OperationError("msg").left())
getEurobonusDataUseCase.responseTurbine.add(ApolloOperationError.OperationError.Other("msg").left())
assertThat(awaitItem()).isEqualTo(
EurobonusUiState(
canSubmit = false,
Expand Down Expand Up @@ -151,7 +151,7 @@ class EurobonusPresenterTest {
awaitItem()
sendEvent(EurobonusEvent.SubmitEditedEurobonus)
awaitItem()
updateEurobonusNumberUseCase.responseTurbine.add(ApolloOperationError.OperationError("msg").left())
updateEurobonusNumberUseCase.responseTurbine.add(ApolloOperationError.OperationError.Other("msg").left())
assertThat(awaitItem().hasError).isEqualTo(true)
}
}
Expand Down

0 comments on commit ab3a8bb

Please sign in to comment.