Skip to content

Added validation for argument default value compatibility #8366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public void Validate(
EnsureFieldNamesAreValid(objectType, errors);
EnsureInterfacesAreCorrectlyImplemented(objectType, errors);
EnsureArgumentDeprecationIsValid(objectType, errors);
EnsureArgumentDefaultValuesAreCompatible(objectType, errors);

if (nodeType?.IsAssignableFrom(objectType) == true)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace HotChocolate.Configuration.Validation;

internal static class TypeValidationHelper
{
private static readonly InputParser s_inputParser = new();

public static void EnsureTypeHasFields(
IComplexTypeDefinition type,
ICollection<ISchemaError> errors)
Expand Down Expand Up @@ -47,6 +49,29 @@ public static void EnsureArgumentDeprecationIsValid(
}
}

public static void EnsureArgumentDefaultValuesAreCompatible(
ObjectType type,
ICollection<ISchemaError> errors)
{
foreach (var field in type.Fields)
{
foreach (var argument in field.Arguments)
{
if (argument.DefaultValue is not null)
{
try
{
s_inputParser.ParseLiteral(argument.DefaultValue, argument);
}
catch (SerializationException)
{
errors.Add(ArgumentDefaultValueMustBeCompatible(type, field, argument));
}
}
}
}
}

public static void EnsureArgumentDeprecationIsValid(
IDirectiveDefinition type,
ICollection<ISchemaError> errors)
Expand Down
2,382 changes: 1,690 additions & 692 deletions src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/HotChocolate/Core/src/Types/Properties/TypeResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,9 @@ Type: `{0}`</value>
<data name="ErrorHelper_RequiredArgumentCannotBeDeprecated" xml:space="preserve">
<value>Required argument {0} cannot be deprecated.</value>
</data>
<data name="ErrorHelper_ArgumentDefaultValueMustBeCompatible" xml:space="preserve">
<value>Argument {0} must have a compatible default value.</value>
</data>
<data name="ErrorHelper_RequiredFieldCannotBeDeprecated" xml:space="preserve">
<value>Required input field {0} cannot be deprecated.</value>
</data>
Expand Down
14 changes: 14 additions & 0 deletions src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,20 @@ public static ISchemaError RequiredArgumentCannotBeDeprecated(
.SetSpecifiedBy(TypeKind.Directive, rfc: 805)
.Build();

public static ISchemaError ArgumentDefaultValueMustBeCompatible(
IComplexTypeDefinition type,
IOutputFieldDefinition field,
IInputValueDefinition argument)
=> SchemaErrorBuilder.New()
.SetMessage(
ErrorHelper_ArgumentDefaultValueMustBeCompatible,
argument.Coordinate.ToString())
.SetType(type)
.SetField(field)
.SetArgument(argument)
.SetSpecifiedBy(type.Kind, rfc: 793)
.Build();

public static ISchemaError RequiredFieldCannotBeDeprecated(
IInputObjectTypeDefinition type,
IInputValueDefinition field)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,7 @@ public void Argument_Type_IsInferred_From_Parameter()
.AddQueryType<QueryWithIntArg>(
t => t
.Field(f => f.GetBar(1))
.Argument("foo", a => a.DefaultValue(null)))
.Argument("foo", a => a.DefaultValue(0)))
.Create();

// assert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,28 @@ type Foo {
}
");
}

[Fact]
public void AcceptArgumentWithCompatibleDefaultValue()
{
ExpectValid(@"
type Query { stub: String }

type Foo {
field(arg: Int! = 123): String
}
");
}

[Fact]
public void RejectArgumentWithIncompatibleDefaultValue()
{
ExpectError(@"
type Query { stub: String }

type Foo {
field(arg: Int! = { a: 1 }): String
}
");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"message": "Argument Foo.field(arg:) must have a compatible default value.",
"type": "Foo",
"extensions": {
"argument": "arg",
"field": "field",
"rfc": "https://github.com/graphql/graphql-spec/pull/793",
"specifiedBy": "https://spec.graphql.org/October2021/#sec-Objects.Type-Validation"
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
schema {
schema {
query: QueryWithIntArg
}

type QueryWithIntArg {
bar(foo: Int!): String
bar(foo: Int! = 0): String
}
Loading