Skip to content

Instantly share code, notes, and snippets.

@sahalnazar
Last active January 16, 2024 16:38
Show Gist options
  • Save sahalnazar/8d874a5afa7d35430e55d08fe02aafc7 to your computer and use it in GitHub Desktop.
Save sahalnazar/8d874a5afa7d35430e55d08fe02aafc7 to your computer and use it in GitHub Desktop.
GraphQL request handler helper class for Apollo Client in Kotlin
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.Mutation
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.api.Query
import com.apollographql.apollo3.exception.ApolloException
import timber.log.Timber
/**
* This class handles the execution of GraphQL queries and mutations using the Apollo client.
* It provides a mechanism to perform queries and mutations and map the responses to structured results.
*
* @param apolloClient The Apollo client instance used for making GraphQL requests.
*/
class ApolloRequestHandler(private val apolloClient: ApolloClient) {
/**
* Execute a GraphQL query and return a structured result.
*
* @param query The GraphQL query to execute.
* @param mapper The mapper function that converts the query response to a structured result.
* @return A MyResult containing the structured result or an error.
*/
suspend fun <T : Query.Data, R> execute(query: Query<T>, mapper: (T?) -> R): ApiResponse<R> {
return try {
val response = apolloClient.query(query).execute()
if (response.hasErrors()) {
Timber.e(response.errors?.toString())
ApiResponse.Error(response.toErrorList())
} else {
Timber.d(response.data.toString())
ApiResponse.Success(mapper(response.data))
}
} catch (e: ApolloException) {
Timber.e(e.message)
ApiResponse.Error(e.toErrorList())
}
}
/**
* Execute a GraphQL mutation and return a structured result.
*
* @param mutation The GraphQL mutation to execute.
* @param mapper The mapper function that converts the mutation response to a structured result.
* @return A MyResult containing the structured result or an error.
*/
suspend fun <T : Mutation.Data, R> execute(mutation: Mutation<T>, mapper: (T?) -> R): ApiResponse<R> {
return try {
val response = apolloClient.mutation(mutation).execute()
if (response.hasErrors()) {
Timber.e(response.errors?.toString())
ApiResponse.Error(response.toErrorList())
} else {
Timber.d(response.data.toString())
ApiResponse.Success(mapper(response.data))
}
} catch (e: ApolloException) {
Timber.e(e.message)
ApiResponse.Error(e.toErrorList())
}
}
// Convert ApolloResponse errors to a list of error messages
private fun <T : Operation.Data> ApolloResponse<T>.toErrorList() =
errors?.map { it.message }.orEmpty()
// Convert ApolloException to a list containing the exception message
private fun ApolloException.toErrorList() =
this.message?.let { listOf(it) } ?: emptyList()
}
// Sealed class to represent structured result of GraphQL requests
sealed class ApiResponse<out T> {
// Represents success with non-nullable data
data class Success<out T>(val data: T) : ApiResponse<T>()
// Represents errors with a list of error messages
data class Error(val errors: List<String>) : ApiResponse<Nothing>()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment