Skip to content

Commit b6cfd64

Browse files
authored
Merge pull request #455 from timward60/timward/custom-handler-resolver-new
Add support for customized missing field resolver handling
2 parents 4838538 + 8a9e92b commit b6cfd64

File tree

4 files changed

+87
-4
lines changed

4 files changed

+87
-4
lines changed

src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import graphql.kickstart.tools.proxy.*
55
import graphql.kickstart.tools.relay.RelayConnectionFactory
66
import graphql.kickstart.tools.util.JavaType
77
import graphql.kickstart.tools.util.ParameterizedTypeImpl
8+
import graphql.schema.DataFetcher
89
import graphql.schema.DataFetchingEnvironment
910
import graphql.schema.visibility.GraphqlFieldVisibility
1011
import kotlinx.coroutines.Dispatchers
@@ -22,6 +23,7 @@ data class SchemaParserOptions internal constructor(
2223
val contextClass: Class<*>?,
2324
val genericWrappers: List<GenericWrapper>,
2425
val allowUnimplementedResolvers: Boolean,
26+
val missingResolverDataFetcher: DataFetcher<Any?>?,
2527
val objectMapperProvider: PerFieldObjectMapperProvider,
2628
val proxyHandlers: List<ProxyHandler>,
2729
val inputArgumentOptionalDetectOmission: Boolean,
@@ -49,6 +51,7 @@ data class SchemaParserOptions internal constructor(
4951
private val genericWrappers: MutableList<GenericWrapper> = mutableListOf()
5052
private var useDefaultGenericWrappers = true
5153
private var allowUnimplementedResolvers = false
54+
private var missingResolverDataFetcher: DataFetcher<Any?>? = null
5255
private var objectMapperProvider: PerFieldObjectMapperProvider = PerFieldConfiguringObjectMapperProvider()
5356
private val proxyHandlers: MutableList<ProxyHandler> = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler(), WeldProxyHandler())
5457
private var inputArgumentOptionalDetectOmission = false
@@ -83,6 +86,10 @@ data class SchemaParserOptions internal constructor(
8386
this.allowUnimplementedResolvers = allowUnimplementedResolvers
8487
}
8588

89+
fun missingResolverDataFetcher(missingResolverDataFetcher: DataFetcher<Any?>?) = this.apply {
90+
this.missingResolverDataFetcher = missingResolverDataFetcher
91+
}
92+
8693
fun inputArgumentOptionalDetectOmission(inputArgumentOptionalDetectOmission: Boolean) = this.apply {
8794
this.inputArgumentOptionalDetectOmission = inputArgumentOptionalDetectOmission
8895
}
@@ -161,6 +168,7 @@ data class SchemaParserOptions internal constructor(
161168
contextClass,
162169
wrappers,
163170
allowUnimplementedResolvers,
171+
missingResolverDataFetcher,
164172
objectMapperProvider,
165173
proxyHandlers,
166174
inputArgumentOptionalDetectOmission,

src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
6161
}
6262

6363
private fun missingFieldResolver(field: FieldDefinition, searches: List<Search>, scanProperties: Boolean): FieldResolver {
64-
return if (options.allowUnimplementedResolvers) {
65-
log.warn("Missing resolver for field: $field")
64+
return if (options.allowUnimplementedResolvers || options.missingResolverDataFetcher != null) {
65+
if (options.allowUnimplementedResolvers) {
66+
log.warn("Missing resolver for field: $field")
67+
}
6668

6769
MissingFieldResolver(field, options)
6870
} else {

src/main/kotlin/graphql/kickstart/tools/resolver/MissingFieldResolver.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ internal class MissingFieldResolver(
1212
) : FieldResolver(field, FieldResolverScanner.Search(Any::class.java, MissingResolverInfo(), null), options, Any::class.java) {
1313

1414
override fun scanForMatches(): List<TypeClassMatcher.PotentialMatch> = listOf()
15-
16-
override fun createDataFetcher(): DataFetcher<*> = DataFetcher<Any> { TODO("Schema resolver not implemented") }
15+
override fun createDataFetcher(): DataFetcher<*> =
16+
options.missingResolverDataFetcher ?: DataFetcher<Any> { TODO("Schema resolver not implemented") }
1717
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package graphql.kickstart.tools
2+
3+
import graphql.GraphQL
4+
import graphql.kickstart.tools.resolver.FieldResolverError
5+
import graphql.schema.DataFetcher
6+
import graphql.schema.DataFetchingEnvironment
7+
import org.junit.Test
8+
import java.util.*
9+
10+
class MissingFieldResolverTest {
11+
12+
@Test(expected = FieldResolverError::class)
13+
fun `should throw error when a field is missing`() {
14+
SchemaParser.newParser()
15+
.schemaString(
16+
"""
17+
type Query {
18+
implementedField(input: String): String
19+
missingField(input: Int): Int
20+
}
21+
"""
22+
)
23+
.resolvers(object : GraphQLQueryResolver {
24+
fun implementedField(input: Optional<String>) = input.toString()
25+
})
26+
.build()
27+
.makeExecutableSchema()
28+
}
29+
30+
@Test
31+
fun `should call missing resolver data fetcher if provided`() {
32+
val schema = SchemaParser.newParser()
33+
.schemaString(
34+
"""
35+
type Query {
36+
implementedField(input: String): String
37+
missingField(input: Int): Int
38+
}
39+
"""
40+
)
41+
.resolvers(object : GraphQLQueryResolver {
42+
fun implementedField(input: Optional<String>) = input.toString()
43+
})
44+
.options(SchemaParserOptions.newOptions()
45+
.missingResolverDataFetcher(TestMissingResolverDataFetcher())
46+
.build())
47+
.build()
48+
.makeExecutableSchema()
49+
50+
val gql = GraphQL.newGraphQL(schema).build()
51+
52+
val result = gql.execute(
53+
"""
54+
query {
55+
implementedField(input: "test-value")
56+
missingField(input: 1)
57+
}
58+
""")
59+
60+
val expected = mapOf(
61+
"implementedField" to "Optional[test-value]",
62+
"missingField" to 1
63+
)
64+
65+
assertEquals(result.getData(), expected)
66+
}
67+
68+
class TestMissingResolverDataFetcher : DataFetcher<Any?> {
69+
override fun get(env: DataFetchingEnvironment?): Any? {
70+
return env?.getArgument("input")
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)