commonMain.com.apollographql.apollo.interceptor.AutoPersistedQueryInterceptor.kt Maven / Gradle / Ivy
package com.apollographql.apollo.interceptor
import com.apollographql.apollo.AutoPersistedQueryInfo
import com.apollographql.apollo.api.ApolloRequest
import com.apollographql.apollo.api.ApolloResponse
import com.apollographql.apollo.api.Error
import com.apollographql.apollo.api.Mutation
import com.apollographql.apollo.api.Operation
import com.apollographql.apollo.api.http.HttpMethod
import com.apollographql.apollo.exception.AutoPersistedQueriesNotSupported
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
class AutoPersistedQueryInterceptor(
private val httpMethodForHashedQueries: HttpMethod,
private val httpMethodForDocumentQueries: HttpMethod,
) : ApolloInterceptor {
override fun intercept(request: ApolloRequest, chain: ApolloInterceptorChain): Flow> {
val enabled = request.enableAutoPersistedQueries ?: true
if (!enabled) {
return chain.proceed(request)
}
// Always use POST for mutations to avoid hitting HTTP caches
val isMutation = request.operation is Mutation
@Suppress("NAME_SHADOWING")
val request = request.newBuilder()
.httpMethod(if (isMutation) HttpMethod.Post else httpMethodForHashedQueries)
.sendDocument(false)
.sendApqExtensions(true)
.build()
return flow {
val responses = chain.proceed(request)
responses.collect { response ->
when {
isPersistedQueryNotFound(response.errors) -> {
val retryRequest = request
.newBuilder()
.httpMethod(if (isMutation) HttpMethod.Post else httpMethodForDocumentQueries)
.sendDocument(true)
.sendApqExtensions(true)
.build()
emitAll(chain.proceed(retryRequest).map { it.withAutoPersistedQueryInfo(false) })
return@collect
}
isPersistedQueryNotSupported(response.errors) -> {
emit(
ApolloResponse.Builder(request.operation, request.requestUuid)
.exception(AutoPersistedQueriesNotSupported())
.build()
)
return@collect
}
else -> {
emit(response.withAutoPersistedQueryInfo(true))
}
}
}
}
}
private fun ApolloResponse.withAutoPersistedQueryInfo(hit: Boolean) = newBuilder()
.addExecutionContext(AutoPersistedQueryInfo(hit))
.build()
private fun isPersistedQueryNotFound(errors: List?): Boolean {
return errors?.any { it.message.equals(PROTOCOL_NEGOTIATION_ERROR_QUERY_NOT_FOUND, ignoreCase = true) } == true
}
private fun isPersistedQueryNotSupported(errors: List?): Boolean {
return errors?.any { it.message.equals(PROTOCOL_NEGOTIATION_ERROR_NOT_SUPPORTED, ignoreCase = true) } == true
}
companion object {
const val PROTOCOL_NEGOTIATION_ERROR_QUERY_NOT_FOUND = "PersistedQueryNotFound"
const val PROTOCOL_NEGOTIATION_ERROR_NOT_SUPPORTED = "PersistedQueryNotSupported"
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy