From c9bef64ac639885abf5578f0b13d41a5b980c09e Mon Sep 17 00:00:00 2001 From: Jordie Date: Tue, 12 Apr 2022 22:01:23 +0200 Subject: [PATCH 1/3] Add support for defining a default DataFetcherFactory via autoconfig --- .../dgs/autoconfig/DgsAutoConfiguration.kt | 13 +++-- .../autoconfig/DgsAutoConfigurationTest.kt | 35 ++++++++---- .../CustomDataFetcherFactory.kt | 53 +++++++++++++++++++ .../src/test/resources/schema/schema.graphqls | 6 +++ .../graphql/dgs/internal/DgsSchemaProvider.kt | 28 ++++++++-- 5 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt diff --git a/graphql-dgs-spring-boot-oss-autoconfigure/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfiguration.kt b/graphql-dgs-spring-boot-oss-autoconfigure/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfiguration.kt index e0259d9c0..47b6dbb33 100644 --- a/graphql-dgs-spring-boot-oss-autoconfigure/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfiguration.kt +++ b/graphql-dgs-spring-boot-oss-autoconfigure/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfiguration.kt @@ -33,6 +33,7 @@ import graphql.execution.ExecutionStrategy import graphql.execution.instrumentation.ChainedInstrumentation import graphql.execution.instrumentation.Instrumentation import graphql.execution.preparsed.PreparsedDocumentProvider +import graphql.schema.DataFetcherFactory import graphql.schema.GraphQLCodeRegistry import graphql.schema.GraphQLSchema import graphql.schema.idl.TypeDefinitionRegistry @@ -85,8 +86,10 @@ open class DgsAutoConfiguration( preparsedDocumentProvider: PreparsedDocumentProvider, queryValueCustomizer: QueryValueCustomizer ): DgsQueryExecutor { - val queryExecutionStrategy = providedQueryExecutionStrategy.orElse(AsyncExecutionStrategy(dataFetcherExceptionHandler)) - val mutationExecutionStrategy = providedMutationExecutionStrategy.orElse(AsyncSerialExecutionStrategy(dataFetcherExceptionHandler)) + val queryExecutionStrategy = + providedQueryExecutionStrategy.orElse(AsyncExecutionStrategy(dataFetcherExceptionHandler)) + val mutationExecutionStrategy = + providedMutationExecutionStrategy.orElse(AsyncSerialExecutionStrategy(dataFetcherExceptionHandler)) return DefaultDgsQueryExecutor( schema, schemaProvider, @@ -158,7 +161,8 @@ open class DgsAutoConfiguration( dataFetcherExceptionHandler: Optional = Optional.empty(), cookieValueResolver: Optional = Optional.empty(), inputObjectMapper: Optional = Optional.empty(), - entityFetcherRegistry: EntityFetcherRegistry + entityFetcherRegistry: EntityFetcherRegistry, + defaultDataFetcherFactory: Optional> = Optional.empty() ): DgsSchemaProvider { return DgsSchemaProvider( applicationContext, @@ -170,7 +174,8 @@ open class DgsAutoConfiguration( dataFetcherExceptionHandler, cookieValueResolver, inputObjectMapper.orElse(DefaultInputObjectMapper()), - entityFetcherRegistry + entityFetcherRegistry, + defaultDataFetcherFactory ) } diff --git a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt index 827973bcf..fb4d79256 100644 --- a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt +++ b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt @@ -18,6 +18,8 @@ package com.netflix.graphql.dgs.autoconfig import com.netflix.graphql.dgs.DgsQueryExecutor import com.netflix.graphql.dgs.autoconfig.testcomponents.CustomContextBuilderConfig +import com.netflix.graphql.dgs.autoconfig.testcomponents.CustomDataFetcherFactory +import com.netflix.graphql.dgs.autoconfig.testcomponents.CustomDataFetcherFactoryTest import com.netflix.graphql.dgs.autoconfig.testcomponents.CustomInputObjectMapperConfig import com.netflix.graphql.dgs.autoconfig.testcomponents.DataFetcherWithInputObject import com.netflix.graphql.dgs.autoconfig.testcomponents.DataLoaderConfig @@ -31,7 +33,8 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner import org.springframework.core.io.ClassPathResource class DgsAutoConfigurationTest { - private val context = WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(DgsAutoConfiguration::class.java))!! + private val context = + WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(DgsAutoConfiguration::class.java))!! @Test fun noSchemaException() { @@ -40,6 +43,18 @@ class DgsAutoConfigurationTest { } } + @Test + fun setUpCustomDataFetcherFactory() { + context.withUserConfiguration(CustomDataFetcherFactory::class.java, CustomDataFetcherFactoryTest::class.java) + .run { ctx -> + assertThat(ctx).getBean(DgsQueryExecutor::class.java).extracting { + val executeQuery = + it.executeAndExtractJsonPath("query {simpleNested{hello}}", "data.simpleNested.hello") + assertThat(executeQuery).isEqualTo("not world") + } + } + } + @Test fun setsUpQueryExecutorWithDataFetcher() { context.withUserConfiguration(HelloDataFetcherConfig::class.java).run { ctx -> @@ -86,15 +101,15 @@ class DgsAutoConfigurationTest { assertThat(ctx).getBean(DgsQueryExecutor::class.java).extracting { val json = it.executeAndExtractJsonPath( " query availableQueries {\n" + - " __schema {\n" + - " queryType {\n" + - " fields {\n" + - " name\n" + - " description\n" + - " }\n" + - " }\n" + - " }\n" + - "}", + " __schema {\n" + + " queryType {\n" + + " fields {\n" + + " name\n" + + " description\n" + + " }\n" + + " }\n" + + " }\n" + + "}", "data.__schema.queryType.fields[0].name" ) assertThat(json).isEqualTo("hello") diff --git a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt new file mode 100644 index 000000000..81bc94ce4 --- /dev/null +++ b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2022 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.graphql.dgs.autoconfig.testcomponents + +import com.netflix.graphql.dgs.DgsComponent +import com.netflix.graphql.dgs.DgsData +import graphql.schema.DataFetcher +import graphql.schema.DataFetcherFactories +import graphql.schema.DataFetcherFactory +import graphql.schema.DataFetchingEnvironment +import graphql.schema.FieldCoordinates +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +object TestDataFetcher : DataFetcher { + override fun get(environment: DataFetchingEnvironment): Any { + return "not world" + } +} + +@Configuration +open class CustomDataFetcherFactory { + @Bean + open fun coolDataFetcherFactory(): DataFetcherFactory<*> { + return DataFetcherFactories.useDataFetcher(TestDataFetcher) + } +} + +data class SimpleNested(val hello: String) + +@DgsComponent +class CustomDataFetcherFactoryTest { + @DgsData(parentType = "Query", field = "simpleNested") + fun hello(dfe: DataFetchingEnvironment): SimpleNested { + val coordinates = FieldCoordinates.coordinates("Query", "simpleNested") + val fieldDefinition = dfe.graphQLSchema.getFieldDefinition(coordinates) + return SimpleNested("world") + } +} diff --git a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/resources/schema/schema.graphqls b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/resources/schema/schema.graphqls index 66d420996..d08fef9a2 100644 --- a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/resources/schema/schema.graphqls +++ b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/resources/schema/schema.graphqls @@ -21,6 +21,12 @@ type Query { withIgnoredField(input: Input): Output withIgnoredFieldNested(nestedInput: NestedInput): Output + + simpleNested: SimpleNested! +} + +type SimpleNested { + hello: String! } input Input { diff --git a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt index b152f60b7..c43ccbd8b 100644 --- a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt +++ b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt @@ -31,6 +31,7 @@ import graphql.language.TypeName import graphql.language.UnionTypeDefinition import graphql.schema.Coercing import graphql.schema.DataFetcher +import graphql.schema.DataFetcherFactory import graphql.schema.FieldCoordinates import graphql.schema.GraphQLCodeRegistry import graphql.schema.GraphQLScalarType @@ -72,7 +73,8 @@ class DgsSchemaProvider( private val dataFetcherExceptionHandler: Optional = Optional.empty(), private val cookieValueResolver: Optional = Optional.empty(), private val inputObjectMapper: InputObjectMapper = DefaultInputObjectMapper(), - private val entityFetcherRegistry: EntityFetcherRegistry = EntityFetcherRegistry() + private val entityFetcherRegistry: EntityFetcherRegistry = EntityFetcherRegistry(), + private val defaultDataFetcherFactory: Optional> = Optional.empty() ) { val dataFetcherInstrumentationEnabled = mutableMapOf() @@ -102,11 +104,20 @@ class DgsSchemaProvider( } val federationResolverInstance = - federationResolver.orElseGet { DefaultDgsFederationResolver(entityFetcherRegistry, dataFetcherExceptionHandler) } + federationResolver.orElseGet { + DefaultDgsFederationResolver( + entityFetcherRegistry, + dataFetcherExceptionHandler + ) + } val entityFetcher = federationResolverInstance.entitiesFetcher() val typeResolver = federationResolverInstance.typeResolver() val codeRegistryBuilder = GraphQLCodeRegistry.newCodeRegistry().fieldVisibility(fieldVisibility) + if (defaultDataFetcherFactory.isPresent) { + codeRegistryBuilder.defaultDataFetcher(defaultDataFetcherFactory.get()) + } + val runtimeWiringBuilder = RuntimeWiring.newRuntimeWiring().codeRegistry(codeRegistryBuilder).fieldVisibility(fieldVisibility) @@ -318,7 +329,14 @@ class DgsSchemaProvider( private fun createBasicDataFetcher(method: Method, dgsComponent: Any, isSubscription: Boolean): DataFetcher { return DataFetcher { environment -> val dfe = DgsDataFetchingEnvironment(environment) - val result = DataFetcherInvoker(cookieValueResolver, defaultParameterNameDiscoverer, dfe, dgsComponent, method, inputObjectMapper).invokeDataFetcher() + val result = DataFetcherInvoker( + cookieValueResolver, + defaultParameterNameDiscoverer, + dfe, + dgsComponent, + method, + inputObjectMapper + ).invokeDataFetcher() when { isSubscription -> { result @@ -365,8 +383,8 @@ class DgsSchemaProvider( overrideTypeResolver = dgsComponents.any { component -> component.javaClass.methods.any { method -> method.isAnnotationPresent(DgsTypeResolver::class.java) && - method.getAnnotation(DgsTypeResolver::class.java).name == annotation.name && - component != dgsComponent + method.getAnnotation(DgsTypeResolver::class.java).name == annotation.name && + component != dgsComponent } } } From 150a2a0591ae194d622ce9f6323d8dbb201464eb Mon Sep 17 00:00:00 2001 From: Jordie Date: Tue, 12 Apr 2022 22:12:55 +0200 Subject: [PATCH 2/3] Fmt --- .../dgs/autoconfig/DgsAutoConfigurationTest.kt | 18 +++++++++--------- .../graphql/dgs/internal/DgsSchemaProvider.kt | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt index fb4d79256..112fd8ac8 100644 --- a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt +++ b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsAutoConfigurationTest.kt @@ -101,15 +101,15 @@ class DgsAutoConfigurationTest { assertThat(ctx).getBean(DgsQueryExecutor::class.java).extracting { val json = it.executeAndExtractJsonPath( " query availableQueries {\n" + - " __schema {\n" + - " queryType {\n" + - " fields {\n" + - " name\n" + - " description\n" + - " }\n" + - " }\n" + - " }\n" + - "}", + " __schema {\n" + + " queryType {\n" + + " fields {\n" + + " name\n" + + " description\n" + + " }\n" + + " }\n" + + " }\n" + + "}", "data.__schema.queryType.fields[0].name" ) assertThat(json).isEqualTo("hello") diff --git a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt index c43ccbd8b..91f2f2603 100644 --- a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt +++ b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DgsSchemaProvider.kt @@ -383,8 +383,8 @@ class DgsSchemaProvider( overrideTypeResolver = dgsComponents.any { component -> component.javaClass.methods.any { method -> method.isAnnotationPresent(DgsTypeResolver::class.java) && - method.getAnnotation(DgsTypeResolver::class.java).name == annotation.name && - component != dgsComponent + method.getAnnotation(DgsTypeResolver::class.java).name == annotation.name && + component != dgsComponent } } } From f64d21ce9e2b8d3165283bdad03a0acea6ef6379 Mon Sep 17 00:00:00 2001 From: Jordie Date: Tue, 12 Apr 2022 22:15:28 +0200 Subject: [PATCH 3/3] Remove dead code --- .../dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt index 81bc94ce4..87e368761 100644 --- a/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt +++ b/graphql-dgs-spring-boot-oss-autoconfigure/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/testcomponents/CustomDataFetcherFactory.kt @@ -22,7 +22,6 @@ import graphql.schema.DataFetcher import graphql.schema.DataFetcherFactories import graphql.schema.DataFetcherFactory import graphql.schema.DataFetchingEnvironment -import graphql.schema.FieldCoordinates import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -46,8 +45,6 @@ data class SimpleNested(val hello: String) class CustomDataFetcherFactoryTest { @DgsData(parentType = "Query", field = "simpleNested") fun hello(dfe: DataFetchingEnvironment): SimpleNested { - val coordinates = FieldCoordinates.coordinates("Query", "simpleNested") - val fieldDefinition = dfe.graphQLSchema.getFieldDefinition(coordinates) return SimpleNested("world") } }