Skip to content

Commit 9fe66ba

Browse files
authored
Throw schema exception for mutation fields that do not return a value (#8662)
1 parent 906d9d3 commit 9fe66ba

File tree

6 files changed

+142
-28
lines changed

6 files changed

+142
-28
lines changed

src/HotChocolate/Core/src/Types.Mutations/Properties/MutationResources.Designer.cs

Lines changed: 79 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/HotChocolate/Core/src/Types.Mutations/Properties/MutationResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ Check the attribute `[Input(TypeName= "{2}")]` or the method `.Input(typeName: "
4747
<data name="ThrowHelper_UnknownDirectiveArgument" xml:space="preserve">
4848
<value>`{0}` is not a valid argument of the directive `@mutation`.</value>
4949
</data>
50+
<data name="ThrowHelper_MutationMustReturnValue" xml:space="preserve">
51+
<value>The mutation field '{0}' must return a value.</value>
52+
</data>
5053
</root>

src/HotChocolate/Core/src/Types.Mutations/ThrowHelper.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,10 @@ public static SchemaException UnknownDirectiveArgument(
4747
.SetMessage(ThrowHelper_UnknownDirectiveArgument, argumentName)
4848
.SetCode(ErrorCodes.Schema.UnknownDirectiveArgument)
4949
.Build());
50+
51+
public static SchemaException MutationMustReturnValue(string memberName)
52+
=> new(SchemaErrorBuilder.New()
53+
.SetMessage(ThrowHelper_MutationMustReturnValue, memberName)
54+
.SetCode(ErrorCodes.Schema.MutationMustReturnValue)
55+
.Build());
5056
}

src/HotChocolate/Core/src/Types.Mutations/UseMutationConventionAttribute.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ protected override void OnConfigure(
9292
IObjectFieldDescriptor descriptor,
9393
MemberInfo member)
9494
{
95+
var returnType = member.GetReturnType();
96+
97+
if (returnType == typeof(void) || returnType == typeof(Task) || returnType == typeof(ValueTask))
98+
{
99+
throw ThrowHelper.MutationMustReturnValue(member.Name);
100+
}
101+
95102
descriptor.Extend().OnBeforeNaming(
96103
(c, d) => c.GetMutationFields().Add(
97104
new MutationContextData(d,

src/HotChocolate/Core/test/Types.Mutations.Tests/AnnotationBasedMutations.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,28 @@ async Task Act() =>
13221322
exception?.Errors[0].Message);
13231323
}
13241324

1325+
[Theory]
1326+
[InlineData(typeof(MutationWithVoidResult))]
1327+
[InlineData(typeof(MutationWithTaskResult))]
1328+
[InlineData(typeof(MutationWithValueTaskResult))]
1329+
public async Task Mutation_NotReturningValue_ThrowsSchemaException(Type mutationType)
1330+
{
1331+
// arrange
1332+
async Task Act() =>
1333+
await new ServiceCollection()
1334+
.AddGraphQL()
1335+
.AddMutationType(mutationType)
1336+
.BuildSchemaAsync();
1337+
1338+
// act & assert
1339+
var exception =
1340+
(SchemaException?)(await Assert.ThrowsAsync<SchemaException>(Act)).Errors[0].Exception;
1341+
1342+
Assert.Equal(
1343+
"The mutation field 'DoSomething' must return a value.",
1344+
exception?.Errors[0].Message);
1345+
}
1346+
13251347
public class ExplicitMutation
13261348
{
13271349
public FieldResult<int, ExplicitCustomError> DoSomething(int status)
@@ -1852,6 +1874,26 @@ public interface IErrorInterface
18521874
public string Message { get; }
18531875
}
18541876

1877+
public class MutationWithVoidResult
1878+
{
1879+
[UseMutationConvention]
1880+
public void DoSomething()
1881+
{
1882+
}
1883+
}
1884+
1885+
public class MutationWithTaskResult
1886+
{
1887+
[UseMutationConvention]
1888+
public Task DoSomething() => Task.CompletedTask;
1889+
}
1890+
1891+
public class MutationWithValueTaskResult
1892+
{
1893+
[UseMutationConvention]
1894+
public ValueTask DoSomething() => ValueTask.CompletedTask;
1895+
}
1896+
18551897
public class CustomNamingConvention : DefaultNamingConventions
18561898
{
18571899
public override string GetArgumentName(ParameterInfo parameter)

src/HotChocolate/Primitives/src/Primitives/ErrorCodes.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ public static class Schema
253253
/// The specified directive argument does not exist.
254254
/// </summary>
255255
public const string UnknownDirectiveArgument = "HC0072";
256+
257+
/// <summary>
258+
/// A mutation field must return a value.
259+
/// </summary>
260+
public const string MutationMustReturnValue = "HC0089";
256261
}
257262

258263
public static class Scalars

0 commit comments

Comments
 (0)