diff --git a/src/HotChocolate/Core/src/Types/Configuration/Validation/TypeValidationHelper.cs b/src/HotChocolate/Core/src/Types/Configuration/Validation/TypeValidationHelper.cs index e5722d0f851..a60cee483b4 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/Validation/TypeValidationHelper.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/Validation/TypeValidationHelper.cs @@ -31,7 +31,7 @@ public static void EnsureFieldDeprecationIsValid( { var field = type.Fields[i]; - if (field.IsDeprecated && field.Type.IsNonNullType()) + if (field.IsDeprecated && field.Type.IsNonNullType() && field.DefaultValue is null) { errors.Add(RequiredFieldCannotBeDeprecated(type, field)); } @@ -49,7 +49,7 @@ public static void EnsureArgumentDeprecationIsValid( { var argument = field.Arguments[j]; - if (argument.IsDeprecated && argument.Type.IsNonNullType()) + if (argument.IsDeprecated && argument.Type.IsNonNullType() && argument.DefaultValue is null) { errors.Add(RequiredArgumentCannotBeDeprecated(type, field, argument)); } @@ -64,7 +64,7 @@ public static void EnsureArgumentDeprecationIsValid( for (var i = 0; i < type.Arguments.Count; i++) { var argument = type.Arguments[i]; - if (argument.IsDeprecated && argument.Type.IsNonNullType()) + if (argument.IsDeprecated && argument.Type.IsNonNullType() && argument.DefaultValue is null) { errors.Add(RequiredArgumentCannotBeDeprecated(type, argument)); } diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IArgumentDescriptor.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IArgumentDescriptor.cs index 4b895694c30..4cf7a74909f 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IArgumentDescriptor.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IArgumentDescriptor.cs @@ -36,7 +36,7 @@ public interface IArgumentDescriptor /// /// Marks the argument as deprecated /// - /// The argument must be nullable. Non-Nullable arguments cannot be deprecated + /// The argument must be nullable or have a default value. Otherwise the argument cannot be deprecated /// /// /// diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IInputFieldDescriptor.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IInputFieldDescriptor.cs index ef6b8ff5cca..825943107e9 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IInputFieldDescriptor.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IInputFieldDescriptor.cs @@ -33,7 +33,7 @@ public interface IInputFieldDescriptor /// /// Marks the field as deprecated /// - /// The field must be nullable. Non-Nullable field cannot be deprecated + /// The field must be nullable or have a default value. Otherwise the field cannot be deprecated /// /// /// diff --git a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs index 315b871094d..2abe0b09bdc 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs @@ -169,7 +169,9 @@ private static IReadOnlyList CreateInputValues( CreateDescription(field.Description), CreateTypeReference(field.Type), ParseDefaultValue(field.DefaultValue), - Array.Empty() + CreateDeprecatedDirective( + field.IsDeprecated, + field.DeprecationReason) )); } diff --git a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionQueryBuilder.cs b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionQueryBuilder.cs index 1c98db8f8ec..842c4fef2a8 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionQueryBuilder.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionQueryBuilder.cs @@ -170,7 +170,7 @@ private static FragmentDefinitionNode BuildFullTypeFragment(bool includeDeprecat new FieldNode("name"), new FieldNode("description"), CreateFields(includeDeprecatedArgs), - CreateInputFields(), + CreateInputFields(includeDeprecatedArgs), CreateInterfacesField(), CreateEnumValuesField(), CreatePossibleTypesField(), @@ -250,21 +250,41 @@ private static FieldNode CreateTypeField() Array.Empty()), })); - private static FieldNode CreateInputFields() - => new FieldNode( - new NameNode("inputFields"), - null, - null, - Array.Empty(), - Array.Empty(), - new SelectionSetNode( - new ISelectionNode[] + private static FieldNode CreateInputFields(bool includeDeprecatedFields) + => includeDeprecatedFields + ? new FieldNode( + new NameNode("inputFields"), + null, + null, + Array.Empty(), + new[] { - new FragmentSpreadNode( - null, - new NameNode("InputValue"), - Array.Empty()), - })); + new ArgumentNode("includeDeprecated", true), + }, + new SelectionSetNode( + new ISelectionNode[] + { + new FragmentSpreadNode( + null, + new NameNode("InputValue"), + Array.Empty()), + new FieldNode("isDeprecated"), + new FieldNode("deprecationReason"), + })) + : new FieldNode( + new NameNode("inputFields"), + null, + null, + Array.Empty(), + Array.Empty(), + new SelectionSetNode( + new ISelectionNode[] + { + new FragmentSpreadNode( + null, + new NameNode("InputValue"), + Array.Empty()), + })); private static FieldNode CreateInterfacesField() => new FieldNode( diff --git a/src/HotChocolate/Utilities/src/Utilities.Introspection/Models/InputField.cs b/src/HotChocolate/Utilities/src/Utilities.Introspection/Models/InputField.cs index 3fddfd51bc4..324a60aa8a8 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Introspection/Models/InputField.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Introspection/Models/InputField.cs @@ -9,5 +9,7 @@ internal class InputField public string Description { get; set; } public TypeRef Type { get; set; } public string DefaultValue { get; set; } + public bool IsDeprecated { get; set; } + public string DeprecationReason { get; set; } } #pragma warning restore CA1812 diff --git a/src/HotChocolate/Utilities/test/Utilities.Introspection.Tests/__snapshots__/IntrospectionQueryBuilderTests.Create_Query_With_ArgumentDeprecation.snap b/src/HotChocolate/Utilities/test/Utilities.Introspection.Tests/__snapshots__/IntrospectionQueryBuilderTests.Create_Query_With_ArgumentDeprecation.snap index ce4fa253c33..c8b3cc4084b 100644 --- a/src/HotChocolate/Utilities/test/Utilities.Introspection.Tests/__snapshots__/IntrospectionQueryBuilderTests.Create_Query_With_ArgumentDeprecation.snap +++ b/src/HotChocolate/Utilities/test/Utilities.Introspection.Tests/__snapshots__/IntrospectionQueryBuilderTests.Create_Query_With_ArgumentDeprecation.snap @@ -40,8 +40,10 @@ fragment FullType on __Type { isDeprecated deprecationReason } - inputFields { + inputFields(includeDeprecated: true) { ... InputValue + isDeprecated + deprecationReason } interfaces { ... TypeRef diff --git a/website/src/docs/hotchocolate/v13/defining-a-schema/versioning.md b/website/src/docs/hotchocolate/v13/defining-a-schema/versioning.md index d5c0cb6ab74..4a23bc824d0 100644 --- a/website/src/docs/hotchocolate/v13/defining-a-schema/versioning.md +++ b/website/src/docs/hotchocolate/v13/defining-a-schema/versioning.md @@ -17,9 +17,9 @@ type Query { ``` -# Deprecating fields +# Deprecation -Fields can be deprecated like the following. +You can deprecate output fields, input fields, arguments and enum values. @@ -35,6 +35,8 @@ public class Query } ``` +> Note: .NET's `[Obsolete("reason")]` attribute is handled in the same way as `[GraphQLDeprecated("reason")]`. + @@ -70,4 +72,5 @@ services -> Note: It is currently not possible to deprecate input values, such as arguments. + +> Warning: You can not deprecate non-null arguments or input fields without a default value.