diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt index 4141cdef..f1bb8009 100644 --- a/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt +++ b/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt @@ -3,6 +3,7 @@ package graphql.kickstart.tools import com.fasterxml.jackson.databind.ObjectMapper import graphql.kickstart.tools.proxy.* import graphql.kickstart.tools.relay.RelayConnectionFactory +import graphql.kickstart.tools.resolver.MissingResolverDataFetcherProvider import graphql.kickstart.tools.util.JavaType import graphql.kickstart.tools.util.ParameterizedTypeImpl import graphql.schema.DataFetcher @@ -23,7 +24,9 @@ data class SchemaParserOptions internal constructor( val contextClass: Class<*>?, val genericWrappers: List, val allowUnimplementedResolvers: Boolean, + @Deprecated("Use missingResolverDataFetcherProvider instead.") val missingResolverDataFetcher: DataFetcher?, + val missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider?, val objectMapperProvider: PerFieldObjectMapperProvider, val proxyHandlers: List, val inputArgumentOptionalDetectOmission: Boolean, @@ -53,6 +56,7 @@ data class SchemaParserOptions internal constructor( private var useDefaultGenericWrappers = true private var allowUnimplementedResolvers = false private var missingResolverDataFetcher: DataFetcher? = null + private var missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider? = null private var objectMapperProvider: PerFieldObjectMapperProvider = PerFieldConfiguringObjectMapperProvider() private val proxyHandlers: MutableList = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler(), WeldProxyHandler()) private var inputArgumentOptionalDetectOmission = false @@ -88,10 +92,15 @@ data class SchemaParserOptions internal constructor( this.allowUnimplementedResolvers = allowUnimplementedResolvers } + @Deprecated("Use missingResolverDataFetcherProvider instead.") fun missingResolverDataFetcher(missingResolverDataFetcher: DataFetcher?) = this.apply { this.missingResolverDataFetcher = missingResolverDataFetcher } + fun missingResolverDataFetcherProvider(missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider?) = this.apply { + this.missingResolverDataFetcherProvider = missingResolverDataFetcherProvider + } + fun inputArgumentOptionalDetectOmission(inputArgumentOptionalDetectOmission: Boolean) = this.apply { this.inputArgumentOptionalDetectOmission = inputArgumentOptionalDetectOmission } @@ -175,6 +184,7 @@ data class SchemaParserOptions internal constructor( wrappers, allowUnimplementedResolvers, missingResolverDataFetcher, + missingResolverDataFetcherProvider, objectMapperProvider, proxyHandlers, inputArgumentOptionalDetectOmission, diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt index 8f7a9de9..4cd44985 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt @@ -72,7 +72,9 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) { } private fun missingFieldResolver(field: FieldDefinition, searches: List, scanProperties: Boolean): FieldResolver { - return if (options.allowUnimplementedResolvers || options.missingResolverDataFetcher != null) { + return if (options.allowUnimplementedResolvers + || options.missingResolverDataFetcher != null + || options.missingResolverDataFetcherProvider != null) { if (options.allowUnimplementedResolvers) { log.warn("Missing resolver for field: $field") } diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MissingFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MissingFieldResolver.kt index bb925530..74ed5a75 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MissingFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MissingFieldResolver.kt @@ -11,7 +11,10 @@ internal class MissingFieldResolver( options: SchemaParserOptions ) : FieldResolver(field, FieldResolverScanner.Search(Any::class.java, MissingResolverInfo(), null), options, Any::class.java) { + private val missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider = options.missingResolverDataFetcherProvider + ?: MissingResolverDataFetcherProvider { + _, options -> options.missingResolverDataFetcher ?: DataFetcher { TODO("Schema resolver not implemented") } + } override fun scanForMatches(): List = listOf() - override fun createDataFetcher(): DataFetcher<*> = - options.missingResolverDataFetcher ?: DataFetcher { TODO("Schema resolver not implemented") } + override fun createDataFetcher(): DataFetcher<*> = missingResolverDataFetcherProvider.createDataFetcher(field, options) } diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MissingResolverDataFetcherProvider.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MissingResolverDataFetcherProvider.kt new file mode 100644 index 00000000..b849a624 --- /dev/null +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MissingResolverDataFetcherProvider.kt @@ -0,0 +1,12 @@ +package graphql.kickstart.tools.resolver + +import graphql.kickstart.tools.SchemaParserOptions +import graphql.language.FieldDefinition +import graphql.schema.DataFetcher + +/** + * Provider for missing resolver data fetchers. + */ +fun interface MissingResolverDataFetcherProvider { + fun createDataFetcher(field: FieldDefinition, options: SchemaParserOptions): DataFetcher<*> +} \ No newline at end of file diff --git a/src/test/kotlin/graphql/kickstart/tools/MissingFieldResolverTest.kt b/src/test/kotlin/graphql/kickstart/tools/MissingFieldResolverTest.kt index c71173fe..6a416bb1 100644 --- a/src/test/kotlin/graphql/kickstart/tools/MissingFieldResolverTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/MissingFieldResolverTest.kt @@ -2,6 +2,8 @@ package graphql.kickstart.tools import graphql.GraphQL import graphql.kickstart.tools.resolver.FieldResolverError +import graphql.kickstart.tools.resolver.MissingResolverDataFetcherProvider +import graphql.language.FieldDefinition import graphql.schema.DataFetcher import graphql.schema.DataFetchingEnvironment import org.junit.Test @@ -65,9 +67,63 @@ class MissingFieldResolverTest { assertEquals(result.getData(), expected) } + @Test + fun `should call missing resolver data fetcher provider if provided`() { + val missingResolverDataFetcherProvider = TestMissingResolverDataFetcherProvider(); + val options = SchemaParserOptions.newOptions() + .missingResolverDataFetcherProvider(missingResolverDataFetcherProvider) + .build(); + val schema = SchemaParser.newParser() + .schemaString( + """ + type Query { + implementedField(input: String): String + missingField(input: Int): Int + } + """ + ) + .resolvers(object : GraphQLQueryResolver { + fun implementedField(input: Optional) = input.toString() + }) + .options(options) + .build() + .makeExecutableSchema() + + val gql = GraphQL.newGraphQL(schema).build() + + val result = gql.execute( + """ + query { + implementedField(input: "test-value") + missingField(input: 1) + } + """) + + val expected = mapOf( + "implementedField" to "Optional[test-value]", + "missingField" to 1 + ) + + assertEquals(result.getData(), expected) + + assertEquals(missingResolverDataFetcherProvider.field?.name, "missingField") + assertEquals(missingResolverDataFetcherProvider.options, options) + } + class TestMissingResolverDataFetcher : DataFetcher { override fun get(env: DataFetchingEnvironment?): Any? { return env?.getArgument("input") } } + + class TestMissingResolverDataFetcherProvider : MissingResolverDataFetcherProvider { + var field: FieldDefinition? = null + var options: SchemaParserOptions? = null + + override fun createDataFetcher(field: FieldDefinition, options: SchemaParserOptions): DataFetcher<*> { + this.field = field; + this.options = options; + return TestMissingResolverDataFetcher() + } + } }