Skip to content

Commit f553dd2

Browse files
smyrickShane Myrick
and
Shane Myrick
authored
[3.x.x][generator] Only add directives with valid locations (ExpediaGroup#924)
* Only add directives with valid locations When generating a schema you can have an annotation on any part of the schema, assuming you haven't set the Target, so if you are restricting the directive locations to only specific places they may still be added to the schema and then fail generation as they are added to invalid locations. While this could be viewed as a customer error, this is more of an issue with graphql-kotlin because we can have input and output objects with the same directives and things like the KeyDirective from federation are only valid on output. So in that case we shouldn't fail if someone uses the type as input elsewhere, it will still not be marked as a federation type for the input * Rename function name * Add unit tests for coverage Co-authored-by: Shane Myrick <[email protected]>
1 parent 7f37f24 commit f553dd2

20 files changed

+188
-69
lines changed

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateArgument.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.expediagroup.graphql.generator.extensions.isInterface
2626
import com.expediagroup.graphql.generator.extensions.isListType
2727
import com.expediagroup.graphql.generator.extensions.isUnion
2828
import com.expediagroup.graphql.generator.extensions.safeCast
29+
import graphql.introspection.Introspection.DirectiveLocation
2930
import graphql.schema.GraphQLArgument
3031
import kotlin.reflect.KClass
3132
import kotlin.reflect.KParameter
@@ -49,7 +50,7 @@ internal fun generateArgument(generator: SchemaGenerator, parameter: KParameter)
4950
.description(parameter.getGraphQLDescription())
5051
.type(graphQLType.safeCast())
5152

52-
generateDirectives(generator, parameter).forEach {
53+
generateDirectives(generator, parameter, DirectiveLocation.ARGUMENT_DEFINITION).forEach {
5354
builder.withDirective(it)
5455
}
5556

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateDirective.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.expediagroup.graphql.generator.extensions.getPropertyAnnotations
2121
import com.expediagroup.graphql.generator.extensions.getSimpleName
2222
import com.expediagroup.graphql.generator.extensions.getValidProperties
2323
import com.expediagroup.graphql.generator.extensions.safeCast
24+
import graphql.introspection.Introspection.DirectiveLocation
2425
import graphql.schema.GraphQLArgument
2526
import graphql.schema.GraphQLDirective
2627
import java.lang.reflect.Field
@@ -29,20 +30,27 @@ import kotlin.reflect.KClass
2930
import kotlin.reflect.KProperty
3031
import com.expediagroup.graphql.annotations.GraphQLDirective as GraphQLDirectiveAnnotation
3132

32-
internal fun generateDirectives(generator: SchemaGenerator, element: KAnnotatedElement, parentClass: KClass<*>? = null): List<GraphQLDirective> {
33+
internal fun generateDirectives(
34+
generator: SchemaGenerator,
35+
element: KAnnotatedElement,
36+
location: DirectiveLocation,
37+
parentClass: KClass<*>? = null
38+
): List<GraphQLDirective> {
3339
val annotations = when {
3440
element is KProperty<*> && parentClass != null -> element.getPropertyAnnotations(parentClass)
3541
else -> element.annotations
3642
}
3743

3844
return annotations
3945
.mapNotNull { it.getDirectiveInfo() }
46+
.filter { it.directiveAnnotation.locations.contains(location) }
4047
.map { getDirective(generator, it) }
4148
}
4249

43-
internal fun generateFieldDirectives(generator: SchemaGenerator, field: Field): List<GraphQLDirective> =
50+
internal fun generateEnumValueDirectives(generator: SchemaGenerator, field: Field): List<GraphQLDirective> =
4451
field.annotations
4552
.mapNotNull { it.getDirectiveInfo() }
53+
.filter { it.directiveAnnotation.locations.contains(DirectiveLocation.ENUM_VALUE) }
4654
.map { getDirective(generator, it) }
4755

4856
private fun getDirective(generator: SchemaGenerator, directiveInfo: DirectiveInfo): GraphQLDirective {

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateEnum.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2323
import com.expediagroup.graphql.generator.extensions.getGraphQLName
2424
import com.expediagroup.graphql.generator.extensions.getSimpleName
2525
import com.expediagroup.graphql.generator.extensions.safeCast
26+
import graphql.introspection.Introspection.DirectiveLocation
2627
import graphql.schema.GraphQLEnumType
2728
import graphql.schema.GraphQLEnumValueDefinition
2829
import kotlin.reflect.KClass
@@ -33,7 +34,7 @@ internal fun generateEnum(generator: SchemaGenerator, kClass: KClass<out Enum<*>
3334
enumBuilder.name(kClass.getSimpleName())
3435
enumBuilder.description(kClass.getGraphQLDescription())
3536

36-
generateDirectives(generator, kClass).forEach {
37+
generateDirectives(generator, kClass, DirectiveLocation.ENUM).forEach {
3738
enumBuilder.withDirective(it)
3839
}
3940

@@ -51,7 +52,7 @@ private fun getEnumValueDefinition(generator: SchemaGenerator, enum: Enum<*>, kC
5152
valueBuilder.name(name)
5253
valueBuilder.value(name)
5354

54-
generateFieldDirectives(generator, valueField).forEach {
55+
generateEnumValueDirectives(generator, valueField).forEach {
5556
valueBuilder.withDirective(it)
5657
}
5758

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateFunction.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2424
import com.expediagroup.graphql.generator.extensions.getValidArguments
2525
import com.expediagroup.graphql.generator.extensions.safeCast
2626
import com.expediagroup.graphql.generator.types.utils.getWrappedReturnType
27+
import graphql.introspection.Introspection.DirectiveLocation
2728
import graphql.schema.FieldCoordinates
2829
import graphql.schema.GraphQLFieldDefinition
2930
import graphql.schema.GraphQLOutputType
@@ -40,7 +41,7 @@ internal fun generateFunction(generator: SchemaGenerator, fn: KFunction<*>, pare
4041
builder.withDirective(deprecatedDirectiveWithReason(it))
4142
}
4243

43-
generateDirectives(generator, fn).forEach {
44+
generateDirectives(generator, fn, DirectiveLocation.FIELD_DEFINITION).forEach {
4445
builder.withDirective(it)
4546
}
4647

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateInputObject.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2121
import com.expediagroup.graphql.generator.extensions.getSimpleName
2222
import com.expediagroup.graphql.generator.extensions.getValidProperties
2323
import com.expediagroup.graphql.generator.extensions.safeCast
24+
import graphql.introspection.Introspection.DirectiveLocation
2425
import graphql.schema.GraphQLInputObjectType
2526
import kotlin.reflect.KClass
2627

@@ -30,7 +31,7 @@ internal fun generateInputObject(generator: SchemaGenerator, kClass: KClass<*>):
3031
builder.name(kClass.getSimpleName(isInputClass = true))
3132
builder.description(kClass.getGraphQLDescription())
3233

33-
generateDirectives(generator, kClass).forEach {
34+
generateDirectives(generator, kClass, DirectiveLocation.INPUT_OBJECT).forEach {
3435
builder.withDirective(it)
3536
}
3637

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateInputProperty.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.expediagroup.graphql.generator.SchemaGenerator
2020
import com.expediagroup.graphql.generator.extensions.getPropertyDescription
2121
import com.expediagroup.graphql.generator.extensions.getPropertyName
2222
import com.expediagroup.graphql.generator.extensions.safeCast
23+
import graphql.introspection.Introspection.DirectiveLocation
2324
import graphql.schema.GraphQLInputObjectField
2425
import graphql.schema.GraphQLInputType
2526
import kotlin.reflect.KClass
@@ -35,7 +36,7 @@ internal fun generateInputProperty(generator: SchemaGenerator, prop: KProperty<*
3536
builder.name(prop.getPropertyName(parentClass))
3637
builder.type(graphQLInputType)
3738

38-
generateDirectives(generator, prop, parentClass).forEach {
39+
generateDirectives(generator, prop, DirectiveLocation.INPUT_FIELD_DEFINITION, parentClass).forEach {
3940
builder.withDirective(it)
4041
}
4142

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateInterface.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.expediagroup.graphql.generator.extensions.getValidSuperclasses
2626
import com.expediagroup.graphql.generator.extensions.safeCast
2727
import com.expediagroup.graphql.generator.state.AdditionalType
2828
import graphql.TypeResolutionEnvironment
29+
import graphql.introspection.Introspection.DirectiveLocation
2930
import graphql.schema.GraphQLInterfaceType
3031
import graphql.schema.GraphQLTypeReference
3132
import kotlin.reflect.KClass
@@ -37,7 +38,7 @@ internal fun generateInterface(generator: SchemaGenerator, kClass: KClass<*>): G
3738
builder.name(kClass.getSimpleName())
3839
builder.description(kClass.getGraphQLDescription())
3940

40-
generateDirectives(generator, kClass).forEach {
41+
generateDirectives(generator, kClass, DirectiveLocation.INTERFACE).forEach {
4142
builder.withDirective(it)
4243
}
4344

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateMutation.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.expediagroup.graphql.exceptions.InvalidMutationTypeException
2121
import com.expediagroup.graphql.generator.SchemaGenerator
2222
import com.expediagroup.graphql.generator.extensions.getValidFunctions
2323
import com.expediagroup.graphql.generator.extensions.isNotPublic
24+
import graphql.introspection.Introspection.DirectiveLocation
2425
import graphql.schema.GraphQLObjectType
2526

2627
internal fun generateMutations(generator: SchemaGenerator, mutations: List<TopLevelObject>): GraphQLObjectType? {
@@ -37,7 +38,7 @@ internal fun generateMutations(generator: SchemaGenerator, mutations: List<TopLe
3738
throw InvalidMutationTypeException(mutation.kClass)
3839
}
3940

40-
generateDirectives(generator, mutation.kClass).forEach {
41+
generateDirectives(generator, mutation.kClass, DirectiveLocation.OBJECT).forEach {
4142
mutationBuilder.withDirective(it)
4243
}
4344

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateObject.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import com.expediagroup.graphql.generator.extensions.getValidFunctions
2424
import com.expediagroup.graphql.generator.extensions.getValidProperties
2525
import com.expediagroup.graphql.generator.extensions.getValidSuperclasses
2626
import com.expediagroup.graphql.generator.extensions.safeCast
27+
import graphql.introspection.Introspection.DirectiveLocation
2728
import graphql.schema.GraphQLInterfaceType
2829
import graphql.schema.GraphQLObjectType
2930
import graphql.schema.GraphQLTypeReference
@@ -37,7 +38,7 @@ internal fun generateObject(generator: SchemaGenerator, kClass: KClass<*>): Grap
3738
builder.name(name)
3839
builder.description(kClass.getGraphQLDescription())
3940

40-
generateDirectives(generator, kClass).forEach {
41+
generateDirectives(generator, kClass, DirectiveLocation.OBJECT).forEach {
4142
builder.withDirective(it)
4243
}
4344

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateProperty.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.expediagroup.graphql.generator.extensions.getPropertyDescription
2323
import com.expediagroup.graphql.generator.extensions.getPropertyName
2424
import com.expediagroup.graphql.generator.extensions.getSimpleName
2525
import com.expediagroup.graphql.generator.extensions.safeCast
26+
import graphql.introspection.Introspection.DirectiveLocation
2627
import graphql.schema.FieldCoordinates
2728
import graphql.schema.GraphQLFieldDefinition
2829
import graphql.schema.GraphQLOutputType
@@ -43,7 +44,7 @@ internal fun generateProperty(generator: SchemaGenerator, prop: KProperty<*>, pa
4344
fieldBuilder.withDirective(deprecatedDirectiveWithReason(it))
4445
}
4546

46-
generateDirectives(generator, prop, parentClass).forEach {
47+
generateDirectives(generator, prop, DirectiveLocation.FIELD_DEFINITION, parentClass).forEach {
4748
fieldBuilder.withDirective(it)
4849
}
4950

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateQuery.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.expediagroup.graphql.exceptions.InvalidQueryTypeException
2121
import com.expediagroup.graphql.generator.SchemaGenerator
2222
import com.expediagroup.graphql.generator.extensions.getValidFunctions
2323
import com.expediagroup.graphql.generator.extensions.isNotPublic
24+
import graphql.introspection.Introspection.DirectiveLocation
2425
import graphql.schema.GraphQLObjectType
2526

2627
internal fun generateQueries(generator: SchemaGenerator, queries: List<TopLevelObject>): GraphQLObjectType {
@@ -32,7 +33,7 @@ internal fun generateQueries(generator: SchemaGenerator, queries: List<TopLevelO
3233
throw InvalidQueryTypeException(query.kClass)
3334
}
3435

35-
generateDirectives(generator, query.kClass).forEach {
36+
generateDirectives(generator, query.kClass, DirectiveLocation.OBJECT).forEach {
3637
queryBuilder.withDirective(it)
3738
}
3839

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateSubscription.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.expediagroup.graphql.exceptions.InvalidSubscriptionTypeException
2121
import com.expediagroup.graphql.generator.SchemaGenerator
2222
import com.expediagroup.graphql.generator.extensions.getValidFunctions
2323
import com.expediagroup.graphql.generator.extensions.isNotPublic
24+
import graphql.introspection.Introspection.DirectiveLocation
2425
import graphql.schema.GraphQLObjectType
2526

2627
internal fun generateSubscriptions(generator: SchemaGenerator, subscriptions: List<TopLevelObject>): GraphQLObjectType? {
@@ -38,6 +39,10 @@ internal fun generateSubscriptions(generator: SchemaGenerator, subscriptions: Li
3839
throw InvalidSubscriptionTypeException(kClass)
3940
}
4041

42+
generateDirectives(generator, subscription.kClass, DirectiveLocation.OBJECT).forEach {
43+
subscriptionBuilder.withDirective(it)
44+
}
45+
4146
kClass.getValidFunctions(generator.config.hooks)
4247
.forEach {
4348
if (generator.config.hooks.isValidSubscriptionReturnType(kClass, it).not()) {

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/generateUnion.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2222
import com.expediagroup.graphql.generator.extensions.getSimpleName
2323
import com.expediagroup.graphql.generator.extensions.safeCast
2424
import graphql.TypeResolutionEnvironment
25+
import graphql.introspection.Introspection.DirectiveLocation
2526
import graphql.schema.GraphQLObjectType
2627
import graphql.schema.GraphQLTypeReference
2728
import graphql.schema.GraphQLUnionType
@@ -33,7 +34,7 @@ internal fun generateUnion(generator: SchemaGenerator, kClass: KClass<*>): Graph
3334
builder.name(kClass.getSimpleName())
3435
builder.description(kClass.getGraphQLDescription())
3536

36-
generateDirectives(generator, kClass).forEach {
37+
generateDirectives(generator, kClass, DirectiveLocation.UNION).forEach {
3738
builder.withDirective(it)
3839
}
3940

0 commit comments

Comments
 (0)