Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add GraphQLContextBuilder #1663

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ class GraphQLWebClientTest {
client.execute(HelloWorldQuery())
}
}
assertEquals(500, error.rawStatusCode)
assertEquals(500, error.statusCode.value())
assertEquals("Internal server error", error.responseBodyAsString)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ package com.expediagroup.graphql.examples.server.ktor

import com.expediagroup.graphql.examples.server.ktor.schema.models.User
import com.expediagroup.graphql.generator.extensions.plus
import com.expediagroup.graphql.server.ktor.DefaultKtorGraphQLContextFactory
import com.expediagroup.graphql.server.ktor.execution.context.DefaultKtorGraphQLContextFactory
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import io.ktor.server.request.ApplicationRequest
import graphql.GraphQLContext

/**
* Custom logic for how this example app should create its context given the [ApplicationRequest]
*/
class CustomGraphQLContextFactory : DefaultKtorGraphQLContextFactory() {
override suspend fun generateContext(request: ApplicationRequest): GraphQLContext =
super.generateContext(request).plus(
override suspend fun generateContext(
request: ApplicationRequest,
graphQLRequest: GraphQLServerRequest
): GraphQLContext =
super.generateContext(request, graphQLRequest).plus(
mutableMapOf<Any, Any>(
"user" to User(
email = "fake@site.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fun Application.graphQLModule() {
)
}
server {
contextFactory = CustomGraphQLContextFactory()
contextProvider = CustomGraphQLContextFactory()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package com.expediagroup.graphql.examples.server.spring.context

import com.expediagroup.graphql.generator.extensions.plus
import com.expediagroup.graphql.server.execution.GraphQLContextFactory
import com.expediagroup.graphql.server.spring.execution.DefaultSpringGraphQLContextFactory
import com.expediagroup.graphql.server.spring.execution.context.DefaultSpringGraphQLContextFactory
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.ServerRequest
import graphql.GraphQLContext
Expand All @@ -28,8 +28,11 @@ import graphql.GraphQLContext
*/
@Component
class MyGraphQLContextFactory : DefaultSpringGraphQLContextFactory() {
override suspend fun generateContext(request: ServerRequest): GraphQLContext =
super.generateContext(request) + mapOf(
override suspend fun generateContext(
request: ServerRequest,
graphQLRequest: GraphQLServerRequest
): GraphQLContext =
super.generateContext(request, graphQLRequest) + mapOf(
"myCustomValue" to (request.headers().firstHeader("MyHeader") ?: "defaultContext")
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import com.expediagroup.graphql.generator.SchemaGeneratorConfig
import com.expediagroup.graphql.generator.TopLevelObject
import com.expediagroup.graphql.generator.scalars.IDValueUnboxer
import com.expediagroup.graphql.generator.toSchema
import com.expediagroup.graphql.server.execution.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.GraphQLRequestHandler
import com.expediagroup.graphql.server.execution.GraphQLRequestParser
import com.expediagroup.graphql.server.execution.GraphQLServer
import com.expediagroup.graphql.server.execution.context.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.context.GraphQLContextProvider
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import com.expediagroup.scalars.queries.ScalarQuery
import com.fasterxml.jackson.databind.ObjectMapper
Expand All @@ -18,9 +19,9 @@ import java.io.IOException

class KtorGraphQLServer(
requestParser: GraphQLRequestParser<ApplicationRequest>,
contextFactory: GraphQLContextFactory<ApplicationRequest>,
contextProvider: GraphQLContextFactory<ApplicationRequest>,
requestHandler: GraphQLRequestHandler
) : GraphQLServer<ApplicationRequest>(requestParser, contextFactory, requestHandler) {
) : GraphQLServer<ApplicationRequest>(requestParser, contextProvider, requestHandler) {

companion object {
operator fun invoke(jacksonObjectMapper: ObjectMapper): KtorGraphQLServer {
Expand All @@ -32,7 +33,7 @@ class KtorGraphQLServer(
throw IOException("Unable to parse GraphQL payload.")
}
}
val contextFactory = object: GraphQLContextFactory<ApplicationRequest> {}
val contextProvider = object: GraphQLContextFactory<ApplicationRequest> {}

val config = SchemaGeneratorConfig(
supportedPackages = listOf("com.expediagroup.scalars"),
Expand All @@ -46,7 +47,7 @@ class KtorGraphQLServer(
.build()
val requestHandler = GraphQLRequestHandler(graphQL)

return KtorGraphQLServer(requestParser, contextFactory, requestHandler)
return KtorGraphQLServer(requestParser, contextProvider, requestHandler)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import com.expediagroup.graphql.generator.SchemaGeneratorConfig
import com.expediagroup.graphql.generator.TopLevelObject
import com.expediagroup.graphql.generator.scalars.IDValueUnboxer
import com.expediagroup.graphql.generator.toSchema
import com.expediagroup.graphql.server.execution.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.GraphQLRequestHandler
import com.expediagroup.graphql.server.execution.GraphQLRequestParser
import com.expediagroup.graphql.server.execution.GraphQLServer
import com.expediagroup.graphql.server.execution.context.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.context.GraphQLContextProvider
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import com.expediagroup.ktor.jackson.queries.HelloWorld
import com.expediagroup.ktor.jackson.queries.ObjectQuery
Expand All @@ -19,9 +20,9 @@ import java.io.IOException

class KtorGraphQLServer(
requestParser: GraphQLRequestParser<ApplicationRequest>,
contextFactory: GraphQLContextFactory<ApplicationRequest>,
contextProvider: GraphQLContextProvider<ApplicationRequest>,
requestHandler: GraphQLRequestHandler
) : GraphQLServer<ApplicationRequest>(requestParser, contextFactory, requestHandler) {
) : GraphQLServer<ApplicationRequest>(requestParser, contextProvider, requestHandler) {

companion object {
operator fun invoke(jacksonObjectMapper: ObjectMapper): KtorGraphQLServer {
Expand All @@ -33,7 +34,7 @@ class KtorGraphQLServer(
throw IOException("Unable to parse GraphQL payload.")
}
}
val contextFactory = object: GraphQLContextFactory<ApplicationRequest> {}
val contextProvider = object: GraphQLContextFactory<ApplicationRequest> {}

val config = SchemaGeneratorConfig(
supportedPackages = listOf("com.expediagroup.ktor.jackson"),
Expand All @@ -47,7 +48,7 @@ class KtorGraphQLServer(
.build()
val requestHandler = GraphQLRequestHandler(graphQL)

return KtorGraphQLServer(requestParser, contextFactory, requestHandler)
return KtorGraphQLServer(requestParser, contextProvider, requestHandler)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import com.expediagroup.graphql.generator.SchemaGeneratorConfig
import com.expediagroup.graphql.generator.TopLevelObject
import com.expediagroup.graphql.generator.scalars.IDValueUnboxer
import com.expediagroup.graphql.generator.toSchema
import com.expediagroup.graphql.server.execution.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.GraphQLRequestHandler
import com.expediagroup.graphql.server.execution.GraphQLRequestParser
import com.expediagroup.graphql.server.execution.GraphQLServer
import com.expediagroup.graphql.server.execution.context.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.context.GraphQLContextProvider
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import com.expediagroup.ktor.kotlinx.queries.HelloWorld
import com.expediagroup.ktor.kotlinx.queries.ObjectQuery
Expand All @@ -19,9 +20,9 @@ import java.io.IOException

class KtorGraphQLServer(
requestParser: GraphQLRequestParser<ApplicationRequest>,
contextFactory: GraphQLContextFactory<ApplicationRequest>,
contextProvider: GraphQLContextFactory<ApplicationRequest>,
requestHandler: GraphQLRequestHandler
) : GraphQLServer<ApplicationRequest>(requestParser, contextFactory, requestHandler) {
) : GraphQLServer<ApplicationRequest>(requestParser, contextProvider, requestHandler) {

companion object {
operator fun invoke(jacksonObjectMapper: ObjectMapper): KtorGraphQLServer {
Expand All @@ -33,7 +34,7 @@ class KtorGraphQLServer(
throw IOException("Unable to parse GraphQL payload.")
}
}
val contextFactory = object: GraphQLContextFactory<ApplicationRequest> {}
val contextProvider = object: GraphQLContextFactory<ApplicationRequest> {}

val config = SchemaGeneratorConfig(
supportedPackages = listOf("com.expediagroup.ktor.kotlinx"),
Expand All @@ -47,7 +48,7 @@ class KtorGraphQLServer(
.build()
val requestHandler = GraphQLRequestHandler(graphQL)

return KtorGraphQLServer(requestParser, contextFactory, requestHandler)
return KtorGraphQLServer(requestParser, contextProvider, requestHandler)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package com.expediagroup.polymorphic
import com.expediagroup.graphql.generator.SchemaGeneratorConfig
import com.expediagroup.graphql.generator.TopLevelObject
import com.expediagroup.graphql.generator.toSchema
import com.expediagroup.graphql.server.execution.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.GraphQLRequestHandler
import com.expediagroup.graphql.server.execution.GraphQLRequestParser
import com.expediagroup.graphql.server.execution.GraphQLServer
import com.expediagroup.graphql.server.execution.context.GraphQLContextFactory
import com.expediagroup.graphql.server.execution.context.GraphQLContextProvider
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import com.expediagroup.polymorphic.queries.PolymorphicQuery
import com.fasterxml.jackson.databind.ObjectMapper
Expand All @@ -17,9 +18,9 @@ import java.io.IOException

class KtorGraphQLServer(
requestParser: GraphQLRequestParser<ApplicationRequest>,
contextFactory: GraphQLContextFactory<ApplicationRequest>,
contextProvider: GraphQLContextProvider<ApplicationRequest>,
requestHandler: GraphQLRequestHandler
) : GraphQLServer<ApplicationRequest>(requestParser, contextFactory, requestHandler) {
) : GraphQLServer<ApplicationRequest>(requestParser, contextProvider, requestHandler) {

companion object {
operator fun invoke(jacksonObjectMapper: ObjectMapper): KtorGraphQLServer {
Expand All @@ -31,7 +32,7 @@ class KtorGraphQLServer(
throw IOException("Unable to parse GraphQL payload.")
}
}
val contextFactory = object: GraphQLContextFactory<ApplicationRequest> {}
val contextProvider = object: GraphQLContextFactory<ApplicationRequest> {}

val config = SchemaGeneratorConfig(
supportedPackages = listOf("com.expediagroup.polymorphic")
Expand All @@ -42,7 +43,7 @@ class KtorGraphQLServer(
val graphQL: GraphQL = GraphQL.newGraphQL(graphQLSchema).build()
val requestHandler = GraphQLRequestHandler(graphQL)

return KtorGraphQLServer(requestParser, contextFactory, requestHandler)
return KtorGraphQLServer(requestParser, contextProvider, requestHandler)
}
}
}
2 changes: 1 addition & 1 deletion servers/graphql-kotlin-ktor-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ tasks {
limit {
counter = "INSTRUCTION"
value = "COVEREDRATIO"
minimum = "0.65".toBigDecimal()
minimum = "0.62".toBigDecimal()
}
limit {
counter = "BRANCH"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.expediagroup.graphql.generator.federation.FederatedSchemaGeneratorHoo
import com.expediagroup.graphql.generator.federation.toFederatedSchema
import com.expediagroup.graphql.generator.toSchema
import com.expediagroup.graphql.server.execution.GraphQLRequestHandler
import com.expediagroup.graphql.server.ktor.execution.KtorGraphQLServer
import graphql.GraphQL as GraphQLEngine
import graphql.execution.AsyncExecutionStrategy
import graphql.execution.AsyncSerialExecutionStrategy
Expand Down Expand Up @@ -127,7 +128,7 @@ class GraphQL(config: GraphQLConfiguration) {
// TODO cannot override the request handler/server as it requires access to graphql engine
val server: KtorGraphQLServer = KtorGraphQLServer(
requestParser = config.server.requestParser,
contextFactory = config.server.contextFactory,
contextProvider = config.server.contextProvider,
requestHandler = GraphQLRequestHandler(
graphQL = engine,
dataLoaderRegistryFactory = config.engine.dataLoaderRegistryFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import com.expediagroup.graphql.generator.hooks.NoopSchemaGeneratorHooks
import com.expediagroup.graphql.generator.hooks.SchemaGeneratorHooks
import com.expediagroup.graphql.generator.scalars.IDValueUnboxer
import com.expediagroup.graphql.server.Schema
import com.expediagroup.graphql.server.execution.context.GraphQLContextProvider
import com.expediagroup.graphql.server.ktor.execution.KtorGraphQLRequestParser
import com.expediagroup.graphql.server.ktor.execution.context.DefaultKtorGraphQLContextFactory
import com.expediagroup.graphql.server.operations.Mutation
import com.expediagroup.graphql.server.operations.Query
import com.fasterxml.jackson.databind.ObjectMapper
Expand All @@ -38,6 +41,7 @@ import graphql.execution.preparsed.PreparsedDocumentProvider
import io.ktor.server.config.ApplicationConfig
import io.ktor.server.config.tryGetString
import io.ktor.server.config.tryGetStringList
import io.ktor.server.request.ApplicationRequest

/**
* Configuration properties that define supported GraphQL configuration options.
Expand Down Expand Up @@ -79,7 +83,7 @@ import io.ktor.server.config.tryGetStringList
* preparsedDocumentProvider = null
* }
* server {
* contextFactory = DefaultKtorGraphQLContextFactory()
* contextProvider = DefaultKtorGraphQLContextFactory()
* jacksonConfiguration = { }
* requestParser = KtorGraphQLRequestParser(jacksonObjectMapper())
* streamingResponse = true
Expand Down Expand Up @@ -274,7 +278,7 @@ class GraphQLConfiguration(config: ApplicationConfig) {
class ServerConfiguration(config: ApplicationConfig) {
// TODO support custom servers/request handlers
/** Custom GraphQL context factory */
var contextFactory: KtorGraphQLContextFactory = DefaultKtorGraphQLContextFactory()
var contextProvider: GraphQLContextProvider<ApplicationRequest> = DefaultKtorGraphQLContextFactory()
/** Custom Jackson ObjectMapper configuration */
var jacksonConfiguration: ObjectMapper.() -> Unit = {}
/** Custom request parser */
Expand Down Expand Up @@ -303,7 +307,7 @@ class GraphQLConfiguration(config: ApplicationConfig) {
var keepAliveInterval: Long? = config.tryGetString("graphql.routing.subscriptions.keepAliveInterval")?.toLongOrNull()
}

/** Configuration for various GraphhQL tools*/
/** Configuration for various GraphQL tools*/
class ToolsConfiguration(config: ApplicationConfig) {
/** GraphiQL IDE configuration */
val graphiql: GraphiQLConfiguration = GraphiQLConfiguration(config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
* limitations under the License.
*/

package com.expediagroup.graphql.server.ktor
package com.expediagroup.graphql.server.ktor.execution

import com.expediagroup.graphql.server.execution.GraphQLRequestParser
import com.expediagroup.graphql.server.types.GraphQLRequest
import com.expediagroup.graphql.server.types.GraphQLServerRequest
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.type.MapType
import com.fasterxml.jackson.databind.type.TypeFactory
import com.fasterxml.jackson.module.kotlin.readValue
import io.ktor.http.HttpMethod
import io.ktor.server.request.ApplicationRequest
import io.ktor.server.request.receiveText
Expand All @@ -47,7 +48,7 @@ class KtorGraphQLRequestParser(
else -> null
}

private fun parseGetRequest(request: ApplicationRequest): GraphQLServerRequest? {
private fun parseGetRequest(request: ApplicationRequest): GraphQLServerRequest {
val query = request.queryParameters[REQUEST_PARAM_QUERY] ?: throw IllegalStateException("Invalid HTTP request - GET request has to specify query parameter")
if (query.startsWith("mutation ") || query.startsWith("subscription ")) {
throw UnsupportedOperationException("Invalid GraphQL operation - only queries are supported for GET requests")
Expand All @@ -62,7 +63,7 @@ class KtorGraphQLRequestParser(

private suspend fun parsePostRequest(request: ApplicationRequest): GraphQLServerRequest? = try {
val rawRequest = request.call.receiveText()
mapper.readValue(rawRequest, GraphQLServerRequest::class.java)
mapper.readValue<GraphQLServerRequest>(rawRequest)
} catch (e: IOException) {
throw IllegalStateException("Invalid HTTP request - unable to parse GraphQL request from POST payload")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@
* limitations under the License.
*/

package com.expediagroup.graphql.server.ktor
package com.expediagroup.graphql.server.ktor.execution

import com.expediagroup.graphql.server.execution.GraphQLRequestHandler
import com.expediagroup.graphql.server.execution.GraphQLServer
import com.expediagroup.graphql.server.execution.context.GraphQLContextProvider
import io.ktor.server.request.ApplicationRequest

/**
* Helper method for how this Ktor example creates the common [GraphQLServer] object that
* can handle requests.
* Ktor specific server implementation.
*/
class KtorGraphQLServer(
requestParser: KtorGraphQLRequestParser,
contextFactory: KtorGraphQLContextFactory,
contextProvider: GraphQLContextProvider<ApplicationRequest>,
requestHandler: GraphQLRequestHandler
) : GraphQLServer<ApplicationRequest>(requestParser, contextFactory, requestHandler)
) : GraphQLServer<ApplicationRequest>(
requestParser,
contextProvider,
requestHandler
)
Loading