Skip to content

Commit 2f3564e

Browse files
smyrickShane Myrickdariuszkuc
authored
Remove GraphQLID annotation for ID class (ExpediaGroup#700)
* Add ID wrapper class Add a simple wrapper class that will allow us to support List<ID> Fixes ExpediaGroup#698 * Remove @GraphQLID annotation * Add more unit tests for coverage * Update docs/writing-schemas/scalars.md Co-authored-by: Dariusz Kuc <[email protected]> * Update docs to match example code * Update docs language Co-authored-by: Shane Myrick <[email protected]> Co-authored-by: Dariusz Kuc <[email protected]>
1 parent 0328a6a commit 2f3564e

File tree

23 files changed

+105
-187
lines changed

23 files changed

+105
-187
lines changed

docs/writing-schemas/annotations.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ title: Annotations
66
`graphql-kotlin-schema-generator` ships with a number of annotation classes to allow you to enhance your GraphQL schema
77
for things that can't be directly derived from Kotlin reflection.
88

9-
* [@GraphQLContext](../execution/contextual-data) - Autowire `GraphQLContext` from the environment
109
* [@GraphQLDescription](../customizing-schemas/documenting-fields) - Provide a description for a GraphQL field
1110
* [@GraphQLDirective](../customizing-schemas/directives) - Registers directive on a GraphQL field
12-
* [@GraphQLID](scalars#id) - Marks given field as GraphQL `ID`
1311
* [@GraphQLIgnore](../customizing-schemas/excluding-fields) - Exclude field from the GraphQL schema
1412
* [@GraphQLName](../customizing-schemas/renaming-fields) - Override the name used for the type
1513
* Kotlin built in [@Deprecated](../customizing-schemas/deprecating-schema) - Apply the GraphQL `@deprecated` directive on the field

docs/writing-schemas/scalars.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,39 @@ extended scalar types provided by `graphql-java`.
2424
2525
## ID
2626

27-
GraphQL supports a the scalar type ID, a unique identifier that is not intended to be human readable. ID's are
28-
serialized as a String. To mark given field as an ID field you have to annotate it with `@GraphQLID` annotation.
27+
GraphQL supports the scalar type `ID`, a unique identifier that is not intended to be human readable. IDs are
28+
serialized as a `String`. To expose a GraphQL `ID` field, you must use the `com.expediagroup.graphql.types.ID` class, which wraps the underlying `String` value.
29+
2930

3031
> NOTE: `graphql-java` supports additional types (`String`, `Int`, `Long`, or `UUID`) but [due to serialization issues](https://github.com/ExpediaGroup/graphql-kotlin/issues/317) we can only directly support Strings. You can still use a type like UUID internally just as long as you convert or parse the value yourself and handle the errors.
3132
3233
```kotlin
3334
data class Person(
34-
@GraphQLID
35-
val id: String,
36-
val name: String
35+
val id: ID,
36+
val name: String
3737
)
3838

39-
fun locatePerson(@GraphQLID id: String) = Person(id, "Jane Doe")
39+
fun findPersonById(id: ID) = Person(id, "John Smith")
4040

41-
@GraphQLID
42-
fun generateRandomId() = UUID.randomUUID().toString()
41+
fun generateRandomId(): ID = ID(UUID.randomUUID().toString())
4342
```
4443

4544
This would produce the following schema:
4645

4746
```graphql
4847
schema {
49-
query: Query
48+
query: Query
5049
}
5150

5251

5352
type Query {
54-
locatePerson(id: ID!): Person!
55-
generateRandomId: ID!
53+
findPersonById(id: ID!): Person!
54+
generateRandomId: ID!
5655
}
5756

5857
type Person {
59-
id: ID!
60-
name: String!
58+
id: ID!
59+
name: String!
6160
}
6261
```
6362

examples/spring/src/main/kotlin/com/expediagroup/graphql/examples/query/ScalarQuery.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package com.expediagroup.graphql.examples.query
1818

1919
import com.expediagroup.graphql.annotations.GraphQLDescription
20-
import com.expediagroup.graphql.annotations.GraphQLID
2120
import com.expediagroup.graphql.spring.operations.Mutation
2221
import com.expediagroup.graphql.spring.operations.Query
22+
import com.expediagroup.graphql.types.ID
2323
import org.springframework.stereotype.Component
2424
import java.util.UUID
2525

@@ -35,11 +35,10 @@ class ScalarQuery : Query {
3535
@GraphQLDescription("Prints a string with a custom scalar as input")
3636
fun printUuids(uuids: List<UUID>) = "You sent $uuids"
3737

38-
fun findPersonById(@GraphQLID id: String) = Person(id, "Nelson")
38+
fun findPersonById(id: ID) = Person(id, "Nelson")
3939

4040
@GraphQLDescription("generates random GraphQL ID")
41-
@GraphQLID
42-
fun generateRandomId() = UUID.randomUUID().toString()
41+
fun generateRandomId() = ID(UUID.randomUUID().toString())
4342
}
4443

4544
@Component
@@ -48,7 +47,6 @@ class ScalarMutation : Mutation {
4847
}
4948

5049
data class Person(
51-
@GraphQLID
52-
val id: String,
50+
val id: ID,
5351
val name: String
5452
)

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/annotations/GraphQLID.kt

Lines changed: 0 additions & 22 deletions
This file was deleted.

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/extensions/annotationExtensions.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.expediagroup.graphql.generator.extensions
1818

1919
import com.expediagroup.graphql.annotations.GraphQLDescription
20-
import com.expediagroup.graphql.annotations.GraphQLID
2120
import com.expediagroup.graphql.annotations.GraphQLIgnore
2221
import com.expediagroup.graphql.annotations.GraphQLName
2322
import kotlin.reflect.KAnnotatedElement
@@ -31,8 +30,6 @@ internal fun KAnnotatedElement.getDeprecationReason(): String? = this.findAnnota
3130

3231
internal fun KAnnotatedElement.isGraphQLIgnored(): Boolean = this.findAnnotation<GraphQLIgnore>() != null
3332

34-
internal fun KAnnotatedElement.isGraphQLID(): Boolean = this.findAnnotation<GraphQLID>() != null
35-
3633
internal fun Deprecated.getReason(): String? {
3734
val builder = StringBuilder()
3835
builder.append(this.message)

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/extensions/kPropertyExtensions.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ import kotlin.reflect.KProperty
2424
* For properties we need to check both the property for annotations and the constructor argument
2525
*/
2626

27-
internal fun KProperty<*>.isPropertyGraphQLID(parentClass: KClass<*>): Boolean = when {
28-
this.isGraphQLID() -> true
29-
getConstructorParameter(parentClass)?.isGraphQLID().isTrue() -> true
30-
else -> false
31-
}
32-
3327
internal fun KProperty<*>.isPropertyGraphQLIgnored(parentClass: KClass<*>): Boolean = when {
3428
this.isGraphQLIgnored() -> true
3529
getConstructorParameter(parentClass)?.isGraphQLIgnored().isTrue() -> true

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import com.expediagroup.graphql.exceptions.InvalidInputFieldTypeException
2020
import com.expediagroup.graphql.generator.SchemaGenerator
2121
import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2222
import com.expediagroup.graphql.generator.extensions.getName
23-
import com.expediagroup.graphql.generator.extensions.isGraphQLID
2423
import com.expediagroup.graphql.generator.extensions.isInterface
2524
import com.expediagroup.graphql.generator.extensions.isList
2625
import com.expediagroup.graphql.generator.extensions.safeCast
@@ -34,7 +33,7 @@ internal fun generateArgument(generator: SchemaGenerator, parameter: KParameter)
3433
throw InvalidInputFieldTypeException(parameter)
3534
}
3635

37-
val graphQLType = generateGraphQLType(generator, parameter.type, inputType = true, annotatedAsID = parameter.isGraphQLID())
36+
val graphQLType = generateGraphQLType(generator = generator, type = parameter.type, inputType = true)
3837

3938
// Deprecation of arguments is currently unsupported: https://github.com/facebook/graphql/issues/197
4039
val builder = GraphQLArgument.newArgument()

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import com.expediagroup.graphql.generator.extensions.getDeprecationReason
2222
import com.expediagroup.graphql.generator.extensions.getFunctionName
2323
import com.expediagroup.graphql.generator.extensions.getGraphQLDescription
2424
import com.expediagroup.graphql.generator.extensions.getValidArguments
25-
import com.expediagroup.graphql.generator.extensions.isGraphQLID
2625
import com.expediagroup.graphql.generator.extensions.safeCast
2726
import com.expediagroup.graphql.generator.types.utils.getWrappedReturnType
2827
import graphql.schema.FieldCoordinates
@@ -51,7 +50,7 @@ internal fun generateFunction(generator: SchemaGenerator, fn: KFunction<*>, pare
5150

5251
val typeFromHooks = generator.config.hooks.willResolveMonad(fn.returnType)
5352
val returnType = getWrappedReturnType(typeFromHooks)
54-
val graphQLOutputType = generateGraphQLType(generator, returnType, annotatedAsID = fn.isGraphQLID()).safeCast<GraphQLOutputType>()
53+
val graphQLOutputType = generateGraphQLType(generator = generator, type = returnType).safeCast<GraphQLOutputType>()
5554
val graphQLType = builder.type(graphQLOutputType).build()
5655
val coordinates = FieldCoordinates.coordinates(parentName, functionName)
5756

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ import kotlin.reflect.KType
3333
/**
3434
* Return a basic GraphQL type given all the information about the kotlin type.
3535
*/
36-
internal fun generateGraphQLType(generator: SchemaGenerator, type: KType, inputType: Boolean = false, annotatedAsID: Boolean = false): GraphQLType {
36+
internal fun generateGraphQLType(generator: SchemaGenerator, type: KType, inputType: Boolean = false): GraphQLType {
3737
val hookGraphQLType = generator.config.hooks.willGenerateGraphQLType(type)
3838
val graphQLType = hookGraphQLType
39-
?: generateScalar(generator, type, annotatedAsID)
39+
?: generateScalar(generator, type)
4040
?: objectFromReflection(generator, type, inputType)
4141

4242
// Do not call the hook on GraphQLTypeReference as we have not generated the type yet

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package com.expediagroup.graphql.generator.types
1919
import com.expediagroup.graphql.generator.SchemaGenerator
2020
import com.expediagroup.graphql.generator.extensions.getPropertyDescription
2121
import com.expediagroup.graphql.generator.extensions.getPropertyName
22-
import com.expediagroup.graphql.generator.extensions.isPropertyGraphQLID
2322
import com.expediagroup.graphql.generator.extensions.safeCast
2423
import graphql.schema.GraphQLInputObjectField
2524
import graphql.schema.GraphQLInputType
@@ -28,7 +27,7 @@ import kotlin.reflect.KProperty
2827

2928
internal fun generateInputProperty(generator: SchemaGenerator, prop: KProperty<*>, parentClass: KClass<*>): GraphQLInputObjectField {
3029
val builder = GraphQLInputObjectField.newInputObjectField()
31-
val graphQLInputType = generateGraphQLType(generator, prop.returnType, true, prop.isPropertyGraphQLID(parentClass)).safeCast<GraphQLInputType>()
30+
val graphQLInputType = generateGraphQLType(generator = generator, type = prop.returnType, inputType = true).safeCast<GraphQLInputType>()
3231

3332
builder.description(prop.getPropertyDescription(parentClass))
3433
builder.name(prop.getPropertyName(parentClass))

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import com.expediagroup.graphql.generator.extensions.getPropertyDeprecationReaso
2222
import com.expediagroup.graphql.generator.extensions.getPropertyDescription
2323
import com.expediagroup.graphql.generator.extensions.getPropertyName
2424
import com.expediagroup.graphql.generator.extensions.getSimpleName
25-
import com.expediagroup.graphql.generator.extensions.isPropertyGraphQLID
2625
import com.expediagroup.graphql.generator.extensions.safeCast
2726
import graphql.schema.FieldCoordinates
2827
import graphql.schema.GraphQLFieldDefinition
@@ -31,7 +30,7 @@ import kotlin.reflect.KClass
3130
import kotlin.reflect.KProperty
3231

3332
internal fun generateProperty(generator: SchemaGenerator, prop: KProperty<*>, parentClass: KClass<*>): GraphQLFieldDefinition {
34-
val propertyType = generateGraphQLType(generator, type = prop.returnType, annotatedAsID = prop.isPropertyGraphQLID(parentClass))
33+
val propertyType = generateGraphQLType(generator, type = prop.returnType)
3534
.safeCast<GraphQLOutputType>()
3635

3736
val fieldBuilder = GraphQLFieldDefinition.newFieldDefinition()

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

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,26 @@
1616

1717
package com.expediagroup.graphql.generator.types
1818

19-
import com.expediagroup.graphql.exceptions.InvalidIdTypeException
2019
import com.expediagroup.graphql.generator.SchemaGenerator
2120
import com.expediagroup.graphql.generator.extensions.getKClass
2221
import com.expediagroup.graphql.generator.extensions.safeCast
22+
import com.expediagroup.graphql.types.ID
2323
import graphql.Scalars
2424
import graphql.schema.GraphQLScalarType
2525
import java.math.BigDecimal
2626
import java.math.BigInteger
2727
import kotlin.reflect.KClass
2828
import kotlin.reflect.KType
29-
import kotlin.reflect.full.isSubclassOf
3029

31-
internal fun generateScalar(generator: SchemaGenerator, type: KType, annotatedAsID: Boolean): GraphQLScalarType? {
32-
val kClass = type.getKClass()
33-
val scalar = when {
34-
annotatedAsID -> getId(kClass)
35-
else -> defaultScalarsMap[kClass]
36-
}
30+
internal fun generateScalar(generator: SchemaGenerator, type: KType): GraphQLScalarType? {
31+
val kClass: KClass<*> = type.getKClass()
32+
val scalar: GraphQLScalarType? = defaultScalarsMap[kClass]
3733

3834
return scalar?.let {
3935
generator.config.hooks.onRewireGraphQLType(it).safeCast()
4036
}
4137
}
4238

43-
@Throws(InvalidIdTypeException::class)
44-
private fun getId(kClass: KClass<*>): GraphQLScalarType? {
45-
return if (kClass.isSubclassOf(String::class)) {
46-
Scalars.GraphQLID
47-
} else {
48-
throw InvalidIdTypeException(kClass)
49-
}
50-
}
51-
5239
private val defaultScalarsMap = mapOf(
5340
Int::class to Scalars.GraphQLInt,
5441
Long::class to Scalars.GraphQLLong,
@@ -59,5 +46,6 @@ private val defaultScalarsMap = mapOf(
5946
BigInteger::class to Scalars.GraphQLBigInteger,
6047
Char::class to Scalars.GraphQLChar,
6148
String::class to Scalars.GraphQLString,
62-
Boolean::class to Scalars.GraphQLBoolean
49+
Boolean::class to Scalars.GraphQLBoolean,
50+
ID::class to Scalars.GraphQLID
6351
)
Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 Expedia, Inc
2+
* Copyright 2020 Expedia, Inc
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,12 +14,16 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.expediagroup.graphql.exceptions
17+
package com.expediagroup.graphql.types
1818

19-
import kotlin.reflect.KClass
19+
import com.fasterxml.jackson.annotation.JsonIgnore
20+
import com.fasterxml.jackson.annotation.JsonValue
2021

2122
/**
22-
* Throws when the KClass is not one of the supported types for a GraphQLID
23+
* Used to represent a GraphQL ID scalar type
24+
* which must serialize/deserialize to a string value
2325
*/
24-
class InvalidIdTypeException(kClass: KClass<*>) :
25-
GraphQLKotlinException("${kClass.simpleName} is not a valid ID type, only Strings are accepted")
26+
data class ID(@get:JsonIgnore val value: String) {
27+
@JsonValue
28+
override fun toString() = value
29+
}

graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/extensions/GraphQLSchemaExtensionsTest.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ package com.expediagroup.graphql.extensions
1919
import com.expediagroup.graphql.TopLevelObject
2020
import com.expediagroup.graphql.annotations.GraphQLDescription
2121
import com.expediagroup.graphql.annotations.GraphQLDirective
22-
import com.expediagroup.graphql.annotations.GraphQLID
2322
import com.expediagroup.graphql.annotations.GraphQLIgnore
2423
import com.expediagroup.graphql.annotations.GraphQLName
2524
import com.expediagroup.graphql.getTestSchemaConfigWithMockedDirectives
2625
import com.expediagroup.graphql.testSchemaConfig
2726
import com.expediagroup.graphql.toSchema
27+
import com.expediagroup.graphql.types.ID
2828
import graphql.introspection.Introspection
2929
import graphql.schema.GraphQLSchema
3030
import org.junit.jupiter.api.Test
@@ -123,12 +123,11 @@ class GraphQLSchemaExtensionsTest {
123123
}
124124

125125
class QueryWithId {
126-
fun queryById(@GraphQLID id: String) = TypeWithId(id, "junit")
126+
fun queryById(id: ID) = TypeWithId(id, "junit")
127127
}
128128

129129
class TypeWithId(
130-
@GraphQLID
131-
val id: String,
130+
val id: ID,
132131
val name: String
133132
)
134133

0 commit comments

Comments
 (0)