Skip to content

Commit e94a756

Browse files
dariuszkucsmyrick
authored andcommitted
[spring-server] support for creating data loader registry per execution (ExpediaGroup#410)
Instance of `DataLoaderRegistry` should be created per GraphQL query execution instead of being a singleton. Developers can create their custom instance of `DataLoaderRegistry` by providing custom `DataLoaderRegistryFactory` bean.
1 parent 5ae8094 commit e94a756

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

graphql-kotlin-spring-server/src/main/kotlin/com/expediagroup/graphql/spring/GraphQLAutoConfiguration.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ package com.expediagroup.graphql.spring
1818

1919
import com.expediagroup.graphql.spring.exception.KotlinDataFetcherExceptionHandler
2020
import com.expediagroup.graphql.spring.execution.ContextWebFilter
21+
import com.expediagroup.graphql.spring.execution.DataLoaderRegistryFactory
2122
import com.expediagroup.graphql.spring.execution.EmptyContextFactory
23+
import com.expediagroup.graphql.spring.execution.EmptyDataLoaderRegistryFactory
2224
import com.expediagroup.graphql.spring.execution.GraphQLContextFactory
2325
import com.expediagroup.graphql.spring.execution.QueryHandler
2426
import com.expediagroup.graphql.spring.execution.SimpleQueryHandler
@@ -32,7 +34,6 @@ import graphql.execution.instrumentation.ChainedInstrumentation
3234
import graphql.execution.instrumentation.Instrumentation
3335
import graphql.execution.preparsed.PreparsedDocumentProvider
3436
import graphql.schema.GraphQLSchema
35-
import org.dataloader.DataLoaderRegistry
3637
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
3738
import org.springframework.boot.context.properties.EnableConfigurationProperties
3839
import org.springframework.context.annotation.Bean
@@ -104,11 +105,14 @@ class GraphQLAutoConfiguration {
104105

105106
@Bean
106107
@ConditionalOnMissingBean
107-
fun dataLoaderRegistry(): DataLoaderRegistry = DataLoaderRegistry()
108+
fun dataLoaderRegistryFactory(): DataLoaderRegistryFactory = EmptyDataLoaderRegistryFactory()
108109

109110
@Bean
110111
@ConditionalOnMissingBean
111-
fun graphQLQueryHandler(graphql: GraphQL, dataLoaderRegistry: DataLoaderRegistry): QueryHandler = SimpleQueryHandler(graphql, dataLoaderRegistry)
112+
fun graphQLQueryHandler(
113+
graphql: GraphQL,
114+
dataLoaderRegistryFactory: DataLoaderRegistryFactory
115+
): QueryHandler = SimpleQueryHandler(graphql, dataLoaderRegistryFactory)
112116

113117
@Bean
114118
@ConditionalOnMissingBean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.expediagroup.graphql.spring.execution
2+
3+
import org.dataloader.DataLoaderRegistry
4+
5+
/**
6+
* Factory used to generate [DataLoaderRegistry] per GraphQL execution.
7+
*/
8+
interface DataLoaderRegistryFactory {
9+
10+
/**
11+
* Generate [DataLoaderRegistry] to be used for GraphQL query execution.
12+
*/
13+
fun generate(): DataLoaderRegistry
14+
}
15+
16+
/**
17+
* Default [DataLoaderRegistryFactory] that generates empty data loader registry.
18+
*/
19+
class EmptyDataLoaderRegistryFactory : DataLoaderRegistryFactory {
20+
override fun generate() = DataLoaderRegistry()
21+
}

graphql-kotlin-spring-server/src/main/kotlin/com/expediagroup/graphql/spring/execution/QueryHandler.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import graphql.GraphQL
2525
import kotlinx.coroutines.ExperimentalCoroutinesApi
2626
import kotlinx.coroutines.future.await
2727
import kotlinx.coroutines.reactor.ReactorContext
28-
import org.dataloader.DataLoaderRegistry
2928
import kotlin.coroutines.coroutineContext
3029

3130
/**
@@ -42,14 +41,14 @@ interface QueryHandler {
4241
/**
4342
* Default GraphQL query handler.
4443
*/
45-
open class SimpleQueryHandler(private val graphql: GraphQL, private val dataLoaderRegistry: DataLoaderRegistry? = null) : QueryHandler {
44+
open class SimpleQueryHandler(private val graphql: GraphQL, private val dataLoaderRegistryFactory: DataLoaderRegistryFactory? = null) : QueryHandler {
4645

4746
@Suppress("TooGenericExceptionCaught")
4847
@ExperimentalCoroutinesApi
4948
override suspend fun executeQuery(request: GraphQLRequest): GraphQLResponse {
5049
val reactorContext = coroutineContext[ReactorContext]
5150
val graphQLContext = reactorContext?.context?.getOrDefault<Any>(GRAPHQL_CONTEXT_KEY, null)
52-
val input = request.toExecutionInput(graphQLContext, dataLoaderRegistry)
51+
val input = request.toExecutionInput(graphQLContext, dataLoaderRegistryFactory?.generate())
5352

5453
return try {
5554
graphql.executeAsync(input)

graphql-kotlin-spring-server/src/test/kotlin/com/expediagroup/graphql/spring/SchemaConfigurationTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.expediagroup.graphql.spring
1818

1919
import com.expediagroup.graphql.SchemaGeneratorConfig
2020
import com.expediagroup.graphql.TopLevelObject
21+
import com.expediagroup.graphql.spring.execution.DataLoaderRegistryFactory
2122
import com.expediagroup.graphql.spring.execution.GraphQLContextFactory
2223
import com.expediagroup.graphql.spring.execution.QueryHandler
2324
import com.expediagroup.graphql.spring.operations.Query
@@ -31,7 +32,6 @@ import graphql.schema.GraphQLSchema
3132
import graphql.schema.GraphQLTypeUtil
3233
import io.mockk.mockk
3334
import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat
34-
import org.dataloader.DataLoaderRegistry
3535
import org.junit.jupiter.api.Test
3636
import org.springframework.boot.autoconfigure.AutoConfigurations
3737
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner
@@ -73,7 +73,7 @@ class SchemaConfigurationTest {
7373
assertNull(result["errors"])
7474
assertNotNull(result["extensions"])
7575

76-
assertThat(ctx).hasSingleBean(DataLoaderRegistry::class.java)
76+
assertThat(ctx).hasSingleBean(DataLoaderRegistryFactory::class.java)
7777
assertThat(ctx).hasSingleBean(QueryHandler::class.java)
7878
assertThat(ctx).hasSingleBean(GraphQLContextFactory::class.java)
7979
}
@@ -97,9 +97,9 @@ class SchemaConfigurationTest {
9797
assertThat(ctx).getBean(GraphQL::class.java)
9898
.isSameAs(customConfiguration.myGraphQL())
9999

100-
assertThat(ctx).hasSingleBean(DataLoaderRegistry::class.java)
101-
assertThat(ctx).getBean(DataLoaderRegistry::class.java)
102-
.isSameAs(customConfiguration.myDataLoaderRegistry())
100+
assertThat(ctx).hasSingleBean(DataLoaderRegistryFactory::class.java)
101+
assertThat(ctx).getBean(DataLoaderRegistryFactory::class.java)
102+
.isSameAs(customConfiguration.myDataLoaderRegistryFactory())
103103

104104
assertThat(ctx).hasSingleBean(QueryHandler::class.java)
105105

@@ -150,7 +150,7 @@ class SchemaConfigurationTest {
150150
fun myCustomContextFactory(): GraphQLContextFactory<Map<String, Any>> = mockk()
151151

152152
@Bean
153-
fun myDataLoaderRegistry(): DataLoaderRegistry = mockk()
153+
fun myDataLoaderRegistryFactory(): DataLoaderRegistryFactory = mockk()
154154
}
155155

156156
class BasicQuery : Query {

0 commit comments

Comments
 (0)