Skip to content

Commit ce8124a

Browse files
authored
Add support for generated @deprecated arguments from @GraphQLDeprecated (ExpediaGroup#2075)
### 📝 Description This PR enables support for using the `@GraphQLDeprecated` annotation on arguments, allowing the generated GraphQL schema to include the `@deprecated` directive. #### Changes: - Updated `generateArgument.kt ` to mark argument as deprecated if the DeprecationReason is present. - Added tests to validate the correct behavior when marking arguments as deprecated. #### Why? The GraphQL spec now officially supports applying `@deprecated` on arguments, enabling better API evolution without breaking existing clients. This change aligns the library with the latest spec, giving developers a built-in way to signal argument deprecations. - [GraphQL Spec - Deprecated Arguments](https://spec.graphql.org/October2021/#sec--deprecated) ](https://spec.graphql.org/draft/#sec--deprecated) ### 🔗 Related Issues ExpediaGroup#1361
1 parent fa6b12d commit ce8124a

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.expediagroup.graphql.generator.internal.types
1818

1919
import com.expediagroup.graphql.generator.SchemaGenerator
2020
import com.expediagroup.graphql.generator.exceptions.InvalidInputFieldTypeException
21+
import com.expediagroup.graphql.generator.internal.extensions.getDeprecationReason
2122
import com.expediagroup.graphql.generator.internal.extensions.getGraphQLDescription
2223
import com.expediagroup.graphql.generator.internal.extensions.getKClass
2324
import com.expediagroup.graphql.generator.internal.extensions.getName
@@ -50,12 +51,15 @@ internal fun generateArgument(generator: SchemaGenerator, parameter: KParameter)
5051
val typeInfo = GraphQLKTypeMetadata(inputType = true, fieldName = parameter.getName(), fieldAnnotations = parameter.annotations)
5152
val graphQLType = generateGraphQLType(generator = generator, type = unwrappedType, typeInfo)
5253

53-
// Deprecation of arguments is currently unsupported: https://youtrack.jetbrains.com/issue/KT-25643
5454
val builder = GraphQLArgument.newArgument()
5555
.name(parameter.getName())
5656
.description(parameter.getGraphQLDescription())
5757
.type(graphQLType.safeCast())
5858

59+
parameter.getDeprecationReason()?.let {
60+
builder.deprecate(it)
61+
}
62+
5963
generateDirectives(generator, parameter, DirectiveLocation.ARGUMENT_DEFINITION).forEach {
6064
builder.withAppliedDirective(it)
6165
}

generator/graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/generator/directives/DirectiveTests.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import graphql.schema.GraphQLNonNull
2828
import graphql.schema.GraphQLObjectType
2929
import org.junit.jupiter.api.Test
3030
import kotlin.test.assertEquals
31+
import kotlin.test.assertFalse
3132
import kotlin.test.assertNotNull
3233
import kotlin.test.assertTrue
3334

@@ -74,6 +75,18 @@ class DirectiveTests {
7475
assertEquals("this query is also deprecated", graphqlDeprecatedQuery.deprecationReason)
7576
}
7677

78+
@Test
79+
fun `SchemaGenerator marks deprecated fields within queries`() {
80+
val schema = toSchema(queries = listOf(TopLevelObject(QueryWithDeprecatedFields())), config = testSchemaConfig())
81+
val topLevelQuery = schema.getObjectType("Query")
82+
val query = topLevelQuery.getFieldDefinition("graphqlQueryWithDeprecatedFields")
83+
84+
assertFalse(query.isDeprecated)
85+
val deprecatedArgument = query.getArgument("something")
86+
assertTrue(deprecatedArgument.isDeprecated)
87+
assertEquals("This field is deprecated", deprecatedArgument.deprecationReason)
88+
}
89+
7790
@Test
7891
fun `Default directive names are normalized`() {
7992
val wiring = object : KotlinSchemaDirectiveWiring {}
@@ -155,6 +168,8 @@ class QueryWithDeprecatedFields {
155168

156169
@Deprecated("this query is also deprecated", replaceWith = ReplaceWith("shinyNewQuery"))
157170
fun graphqlDeprecatedQueryWithReplacement(something: String) = something
171+
172+
fun graphqlQueryWithDeprecatedFields(@GraphQLDeprecated("This field is deprecated") something: String, replacement: String) = "$something -> $replacement"
158173
}
159174

160175
data class ClassWithDeprecatedField(

generator/graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/generator/internal/types/GenerateArgumentTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

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

19+
import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated
1920
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
2021
import com.expediagroup.graphql.generator.annotations.GraphQLName
2122
import com.expediagroup.graphql.generator.exceptions.InvalidInputFieldTypeException
@@ -33,6 +34,7 @@ import kotlin.reflect.full.findParameterByName
3334
import kotlin.test.assertEquals
3435
import kotlin.test.assertFailsWith
3536
import kotlin.test.assertNotNull
37+
import kotlin.test.assertTrue
3638

3739
class GenerateArgumentTest : TypeTestHelper() {
3840

@@ -51,6 +53,8 @@ class GenerateArgumentTest : TypeTestHelper() {
5153

5254
fun changeName(@GraphQLName("newName") input: String) = input
5355

56+
fun deprecate(@GraphQLDeprecated("Deprecated") input: String, replacement: String) = "$input -> $replacement"
57+
5458
fun idClass(idArg: ID) = "Your id is $idArg"
5559

5660
fun interfaceArg(input: MyInterface) = input.id
@@ -108,6 +112,16 @@ class GenerateArgumentTest : TypeTestHelper() {
108112
assertEquals("newName", result.name)
109113
}
110114

115+
@Test
116+
fun `Argument can be deprecated with @GraphqlDeprecated`() {
117+
val kParameter = ArgumentTestClass::deprecate.findParameterByName("input")
118+
assertNotNull(kParameter)
119+
val result = generateArgument(generator, kParameter)
120+
121+
assertTrue(result.isDeprecated, "The argument should be marked as deprecated")
122+
assertEquals("Deprecated", result.deprecationReason, "The deprecation reason should match")
123+
}
124+
111125
@Test
112126
fun `Wrapper ID class argument type is valid`() {
113127
val kParameter = ArgumentTestClass::idClass.findParameterByName("idArg")

website/versioned_docs/version-8.x.x/schema-generator/customizing-schemas/deprecating-schema.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,23 @@ type Query {
3737

3838
A side-effect of using `@Deprecated` is that it marks your own Kotlin code as being deprecated, which may not be what you want. Using `@GraphQLDeprecated` you can add the `@deprecated` directive to the GraphQL schema, but not have your Kotlin code show up as deprecated in your editor.
3939

40+
### Deprecating Fields
4041
```kotlin
4142
class SimpleQuery {
4243
@GraphQLDeprecated(message = "this query is deprecated", replaceWith = ReplaceWith("shinyNewQuery"))
4344
fun simpleDeprecatedQuery(): Boolean = false
4445

4546
fun shinyNewQuery(): Boolean = true
4647
}
48+
```
49+
50+
### Deprecating Arguments
51+
You can also use `@GraphQLDeprecated` to deprecate individual arguments in your GraphQL schema. This allows you to notify clients that a specific argument is deprecated and optionally provide them with guidance on replacement arguments.
52+
53+
```kotlin
54+
class QueryWithDeprecatedArgument {
55+
fun exampleQuery(@GraphQLDeprecated(message = "Use 'newArg' instead") oldArg: String?, newArg: String): String {
56+
return "Received: ${newArg}"
57+
}
58+
}
59+
```

0 commit comments

Comments
 (0)