From 0e1f9b8f812de2ebee3cd95395f3c76fd86f3266 Mon Sep 17 00:00:00 2001 From: Kevin Smithson Date: Thu, 3 Dec 2020 08:43:13 -0800 Subject: [PATCH 1/7] Allow deprecation of input values (#525) Co-authored-by: Ivan Goncharov --- spec/Section 3 -- Type System.md | 9 +++++++-- spec/Section 4 -- Introspection.md | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index b539b936e..e33d3d0b5 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -2047,7 +2047,7 @@ condition is false. ```graphql directive @deprecated( reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE +) on FIELD_DEFINITION | ENUM_VALUE | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` The `@deprecated` _built-in directive_ is used within the type system definition @@ -2058,12 +2058,17 @@ Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by [CommonMark](https://commonmark.org/)). In this example type definition, `oldField` is deprecated in favor of using -`newField`. +`newField` and `oldArg` is deprecated in favor of using `newArg`. ```graphql example type ExampleType { newField: String oldField: String @deprecated(reason: "Use `newField`.") + + existingField( + newArg: String + oldArg: String @deprecated(reason: "Use `newArg`.") + ): String } ``` diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index 9b32133f8..1fc9e53e3 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -145,7 +145,7 @@ type __Type { # must be non-null for ENUM, otherwise null. enumValues(includeDeprecated: Boolean = false): [__EnumValue!] # must be non-null for INPUT_OBJECT, otherwise null. - inputFields: [__InputValue!] + inputFields(includeDeprecated: Boolean = false): [__InputValue!] # must be non-null for NON_NULL and LIST, otherwise null. ofType: __Type # may be non-null for custom SCALAR, otherwise null. @@ -166,7 +166,7 @@ enum __TypeKind { type __Field { name: String! description: String - args: [__InputValue!]! + args(includeDeprecated: Boolean = false): [__InputValue!]! type: __Type! isDeprecated: Boolean! deprecationReason: String @@ -177,6 +177,8 @@ type __InputValue { description: String type: __Type! defaultValue: String + isDeprecated: Boolean! + deprecationReason: String } type __EnumValue { @@ -367,6 +369,8 @@ Fields\: - `name` must return a String. - `description` may return a String or {null}. - `inputFields` must return the set of input fields as a list of `__InputValue`. + - Accepts the argument `includeDeprecated` which defaults to {false}. If + {true}, deprecated fields are also returned. - All other fields must return {null}. **List** @@ -412,6 +416,8 @@ Fields\: - `description` may return a String or {null} - `args` returns a List of `__InputValue` representing the arguments this field accepts. + - Accepts the argument `includeDeprecated` which defaults to {false}. If + {true}, deprecated arguments are also returned. - `type` must return a `__Type` that represents the type of value returned by this field. - `isDeprecated` returns {true} if this field should no longer be used, @@ -432,6 +438,10 @@ Fields\: - `defaultValue` may return a String encoding (using the GraphQL language) of the default value used by this input value in the condition a value is not provided at runtime. If this input value has no default value, returns {null}. +- `isDeprecated` returns {true} if this field or argument should no longer be + used, otherwise {false}. +- `deprecationReason` optionally provides a reason why this input field or + argument is deprecated. ### The \_\_EnumValue Type @@ -483,5 +493,7 @@ Fields\: locations this directive may be placed. - `args` returns a List of `__InputValue` representing the arguments this directive accepts. + - Accepts the argument `includeDeprecated` which defaults to {false}. If + {true}, deprecated arguments are also returned. - `isRepeatable` must return a Boolean that indicates if the directive may be used repeatedly at a single location. From 6ad62e8feb843e1d2ef3a88936cf84e988feab02 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 22 Apr 2021 15:24:42 -0700 Subject: [PATCH 2/7] prose --- spec/Section 4 -- Introspection.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index 1fc9e53e3..9185c2f3e 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -108,9 +108,10 @@ CommonMark-compliant Markdown renderer. **Deprecation** -To support the management of backwards compatibility, GraphQL fields and enum -values can indicate whether or not they are deprecated (`isDeprecated: Boolean`) -and a description of why it is deprecated (`deprecationReason: String`). +To support the management of backwards compatibility, GraphQL fields, arguments, +input fields, and enum values can indicate whether or not they are deprecated +(`isDeprecated: Boolean`) along with a description of why it is deprecated +(`deprecationReason: String`). Tools built using GraphQL introspection should respect deprecation by discouraging deprecated use through information hiding or developer-facing From cce1219f90b26070e82f081c2e0df38148a0ce36 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 22 Apr 2021 15:27:53 -0700 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Ivan Maximov --- spec/Section 4 -- Introspection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index 9185c2f3e..2df2043b9 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -439,8 +439,8 @@ Fields\: - `defaultValue` may return a String encoding (using the GraphQL language) of the default value used by this input value in the condition a value is not provided at runtime. If this input value has no default value, returns {null}. -- `isDeprecated` returns {true} if this field or argument should no longer be - used, otherwise {false}. +- `isDeprecated` returns {true} if this input field or argument should no longer + be used, otherwise {false}. - `deprecationReason` optionally provides a reason why this input field or argument is deprecated. From 23f175cf96d84cc7fde05c8791a1081ec904d5d7 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 22 Apr 2021 15:31:20 -0700 Subject: [PATCH 4/7] Code review --- spec/Section 3 -- Type System.md | 7 ++++--- spec/Section 4 -- Introspection.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index e33d3d0b5..7f29899bc 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -2047,12 +2047,13 @@ condition is false. ```graphql directive @deprecated( reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION +) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE ``` The `@deprecated` _built-in directive_ is used within the type system definition language to indicate deprecated portions of a GraphQL service's schema, such as -deprecated fields on a type or deprecated enum values. +deprecated fields on a type, arguments on a field, input fields on an input +type, or values of an enum type. Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by [CommonMark](https://commonmark.org/)). @@ -2065,7 +2066,7 @@ type ExampleType { newField: String oldField: String @deprecated(reason: "Use `newField`.") - existingField( + anotherField( newArg: String oldArg: String @deprecated(reason: "Use `newArg`.") ): String diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index 2df2043b9..f39e1a9c0 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -193,7 +193,7 @@ type __Directive { name: String! description: String locations: [__DirectiveLocation!]! - args: [__InputValue!]! + args(includeDeprecated: Boolean = false): [__InputValue!]! isRepeatable: Boolean! } From ba78f0040c170bf69db5c14dc247bb342275a515 Mon Sep 17 00:00:00 2001 From: Stephen Spalding Date: Thu, 6 Jan 2022 12:59:22 -0800 Subject: [PATCH 5/7] Add validation for @deprecated on required arguments (#917) The `@deprecated` directive must not appear on required (non-null without a default) arguments or input object field definitions. Deprecated arguments and fields are excluded by default in introspection, and deprecating required arguments or input fields could create confusion for clients. --- spec/Section 3 -- Type System.md | 17 +++++++++++++++++ spec/Section 5 -- Validation.md | 24 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 7f29899bc..df6bc813f 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -2073,6 +2073,23 @@ type ExampleType { } ``` +The `@deprecated` directive must not appear on required (non-null without a +default) arguments or input object field definitions. Deprecated arguments and +fields are excluded by default in introspection, and deprecating required +arguments or input fields could create confusion for clients. + +```graphql counter-example +type ExampleType { + invalidField( + newArg: String + oldArg: String! @deprecated(reason: "Use `newArg`.") + ): String +} +``` + +A required argument or input field should first be made optional by either +changing the type to nullable or adding a default value. + ### @specifiedBy ```graphql diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 4eda8e7b4..076b55d2f 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -736,6 +736,7 @@ invalid. - Let {argumentName} be the name of {argumentDefinition}. - Let {argument} be the argument in {arguments} named {argumentName} - {argument} must exist. + - {argument} must not be deprecated. - Let {value} be the value of {argument}. - {value} must not be the {null} literal. @@ -783,6 +784,18 @@ fragment missingRequiredArg on Arguments { } ``` +If an argument is required (non-null without a default value), it must not be +marked as deprecated. + +```graphql counter-example +type Query { + """ + This is invalid because the locale argument is both required and deprecated. + """ + myName(locale: String! @deprecated): String +} +``` + ## Fragments ### Fragment Declarations @@ -1396,6 +1409,7 @@ For example the following document will not pass validation. - Let {fieldName} be the name of {fieldDefinition}. - Let {field} be the input field in {fields} named {fieldName} - {field} must exist. + - {field} must not be deprecated. - Let {value} be the value of {field}. - {value} must not be the {null} literal. @@ -1406,6 +1420,16 @@ arguments, an input object may have required fields. An input field is required if it has a non-null type and does not have a default value. Otherwise, the input object field is optional. +A required input object field must not be marked as deprecated. + +```graphql counter-example +input Point { + x: Int! + y: Int! + z: Int! @deprecated(reason: "Northward, not upward") +} +``` + ## Directives ### Directives Are Defined From d3dd6f7127175ca0fc900098f69c576faf262fee Mon Sep 17 00:00:00 2001 From: Stephen Spalding Date: Tue, 11 Jan 2022 23:15:35 -0800 Subject: [PATCH 6/7] Move deprecated validation to Section 3 (#922) --- spec/Section 3 -- Type System.md | 8 +++++--- spec/Section 5 -- Validation.md | 24 ------------------------ 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index df6bc813f..7686db7c8 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -879,6 +879,8 @@ of rules must be adhered to by every Object type in a GraphQL schema. {"\_\_"} (two underscores). 2. The argument must accept a type where {IsInputType(argumentType)} returns {true}. + 3. If argument type is Non-Null and a default value is not defined: + - The `@deprecated` directive shall not be applied to this argument. 3. An object type may declare that it implements one or more unique interfaces. 4. An object type must be a super-set of all interfaces it implements: 1. Let this object type be {objectType}. @@ -1652,6 +1654,8 @@ input ExampleInputObject { {"\_\_"} (two underscores). 3. The input field must accept a type where {IsInputType(inputFieldType)} returns {true}. + 4. If input field type is Non-Null and a default value is not defined: + - The `@deprecated` directive shall not be applied to this input field. 3. If an Input Object references itself either directly or through referenced Input Objects, at least one of the fields in the chain of references must be either a nullable or a List type. @@ -2074,9 +2078,7 @@ type ExampleType { ``` The `@deprecated` directive must not appear on required (non-null without a -default) arguments or input object field definitions. Deprecated arguments and -fields are excluded by default in introspection, and deprecating required -arguments or input fields could create confusion for clients. +default) arguments or input object field definitions. ```graphql counter-example type ExampleType { diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 076b55d2f..4eda8e7b4 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -736,7 +736,6 @@ invalid. - Let {argumentName} be the name of {argumentDefinition}. - Let {argument} be the argument in {arguments} named {argumentName} - {argument} must exist. - - {argument} must not be deprecated. - Let {value} be the value of {argument}. - {value} must not be the {null} literal. @@ -784,18 +783,6 @@ fragment missingRequiredArg on Arguments { } ``` -If an argument is required (non-null without a default value), it must not be -marked as deprecated. - -```graphql counter-example -type Query { - """ - This is invalid because the locale argument is both required and deprecated. - """ - myName(locale: String! @deprecated): String -} -``` - ## Fragments ### Fragment Declarations @@ -1409,7 +1396,6 @@ For example the following document will not pass validation. - Let {fieldName} be the name of {fieldDefinition}. - Let {field} be the input field in {fields} named {fieldName} - {field} must exist. - - {field} must not be deprecated. - Let {value} be the value of {field}. - {value} must not be the {null} literal. @@ -1420,16 +1406,6 @@ arguments, an input object may have required fields. An input field is required if it has a non-null type and does not have a default value. Otherwise, the input object field is optional. -A required input object field must not be marked as deprecated. - -```graphql counter-example -input Point { - x: Int! - y: Int! - z: Int! @deprecated(reason: "Northward, not upward") -} -``` - ## Directives ### Directives Are Defined From 127f0ef23b74f6437ab6d4d26678b0b873adfc89 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 2 Jun 2022 22:44:05 -0700 Subject: [PATCH 7/7] Editorial --- spec/Section 3 -- Type System.md | 8 ++++---- spec/Section 4 -- Introspection.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 7686db7c8..0d44913a6 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -880,7 +880,7 @@ of rules must be adhered to by every Object type in a GraphQL schema. 2. The argument must accept a type where {IsInputType(argumentType)} returns {true}. 3. If argument type is Non-Null and a default value is not defined: - - The `@deprecated` directive shall not be applied to this argument. + - The `@deprecated` directive must not be applied to this argument. 3. An object type may declare that it implements one or more unique interfaces. 4. An object type must be a super-set of all interfaces it implements: 1. Let this object type be {objectType}. @@ -1655,7 +1655,7 @@ input ExampleInputObject { 3. The input field must accept a type where {IsInputType(inputFieldType)} returns {true}. 4. If input field type is Non-Null and a default value is not defined: - - The `@deprecated` directive shall not be applied to this input field. + - The `@deprecated` directive must not be applied to this input field. 3. If an Input Object references itself either directly or through referenced Input Objects, at least one of the fields in the chain of references must be either a nullable or a List type. @@ -2089,8 +2089,8 @@ type ExampleType { } ``` -A required argument or input field should first be made optional by either -changing the type to nullable or adding a default value. +To deprecate a required argument or input field, it must first be made optional +by either changing the type to nullable or adding a default value. ### @specifiedBy diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index f39e1a9c0..63a5981b9 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -371,7 +371,7 @@ Fields\: - `description` may return a String or {null}. - `inputFields` must return the set of input fields as a list of `__InputValue`. - Accepts the argument `includeDeprecated` which defaults to {false}. If - {true}, deprecated fields are also returned. + {true}, deprecated input fields are also returned. - All other fields must return {null}. **List**