All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.io.github.jan.supabase.graphql.GraphQL.kt Maven / Gradle / Ivy

There is a newer version: 3.0.3
Show newest version
package io.github.jan.supabase.graphql

import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.network.http.HttpInterceptor
import com.apollographql.apollo3.network.http.HttpInterceptorChain
import io.github.jan.supabase.BuildConfig
import io.github.jan.supabase.SupabaseClient
import io.github.jan.supabase.exceptions.RestException
import io.github.jan.supabase.gotrue.Auth
import io.github.jan.supabase.logging.SupabaseLogger
import io.github.jan.supabase.logging.d
import io.github.jan.supabase.plugins.MainConfig
import io.github.jan.supabase.plugins.MainPlugin
import io.github.jan.supabase.plugins.SupabasePluginProvider
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpHeaders
import com.apollographql.apollo3.api.http.HttpRequest as ApolloHttpRequest
import com.apollographql.apollo3.api.http.HttpResponse as ApolloHttpResponse

/**
 * Adds an Apollo GraphQL client to supabase-kt with all necessary headers automatically managed.
 *
 *
 * This plugin uses the default GraphQL endpoint for supabase projects and adds the `apikey` and `Authorization` headers automatically
 */
sealed interface GraphQL: MainPlugin {

    /**
     * The Apollo Client. Customizable via [Config.apolloConfiguration]
     */
    val apolloClient: ApolloClient

    /**
     * Config for the [GraphQL] plugin
     * @param apolloConfiguration custom apollo client configuration
     */
    data class Config(
        internal var apolloConfiguration: ApolloClient.Builder.() -> Unit = {}
    ): MainConfig() {

        /**
         * Add custom apollo client configuration
         */
        fun apolloConfiguration(configuration: ApolloClient.Builder.() -> Unit) {
            apolloConfiguration = configuration
        }

    }

    companion object: SupabasePluginProvider {

        override val key: String = "graphql"

        override val logger: SupabaseLogger = SupabaseClient.createLogger("Supabase-ApolloGraphQL")

        /**
         * The current graphql api version
         */
        const val API_VERSION = 1

        override fun create(supabaseClient: SupabaseClient, config: Config): GraphQL {
            return GraphQLImpl(config, supabaseClient)
        }

        override fun createConfig(init: Config.() -> Unit): Config {
            return Config().apply(init)
        }

    }

}

internal class GraphQLImpl(override val config: GraphQL.Config, override val supabaseClient: SupabaseClient) : GraphQL {

    override val apiVersion: Int = GraphQL.API_VERSION
    override val pluginKey: String = GraphQL.key
    override val apolloClient = ApolloClient.Builder().apply {
        serverUrl(config.customUrl ?: resolveUrl())
        addHttpHeader("apikey", supabaseClient.supabaseKey)
        addHttpHeader("X-Client-Info", "supabase-kt/${BuildConfig.PROJECT_VERSION}")
        addHttpInterceptor(ApolloHttpInterceptor())
        apply(config.apolloConfiguration)
    }.build()

    override suspend fun parseErrorResponse(response: HttpResponse): RestException {
        throw UnsupportedOperationException("Use apolloClient for GraphQL requests")
    }

    inner class ApolloHttpInterceptor: HttpInterceptor {
        override suspend fun intercept(
            request: ApolloHttpRequest,
            chain: HttpInterceptorChain
        ): ApolloHttpResponse {
            GraphQL.logger.d { "Intercepting Apollo request with url ${request.url}" }
            val accessToken = config.jwtToken ?: supabaseClient.pluginManager.getPluginOrNull(Auth)?.currentAccessTokenOrNull() ?: supabaseClient.supabaseKey
            val newRequest = request.newBuilder().apply {
                addHeader(HttpHeaders.Authorization, "Bearer $accessToken")
            }
            return chain.proceed(newRequest.build())
        }

    }


}

/**
 * With the [GraphQL] plugin installed, you can access a pre-made Apollo GraphQL client via this property
 */
val SupabaseClient.graphql: GraphQL
    get() = pluginManager.getPlugin(GraphQL)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy