Skip to content

Commit 731da82

Browse files
Add operation name to details error mapper (#95)
* Add operation name to details error mapper * Add test case for multiple operations in single mutation
1 parent c9f6b47 commit 731da82

6 files changed

Lines changed: 227 additions & 1 deletion

File tree

src/ValidationDefaults.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
global using HotChocolate.Resolvers;
66
global using FluentValidation;
77
global using FluentValidation.Results;
8-
98
using System.Runtime.CompilerServices;
109
using FluentValidation.Internal;
1110
using HotChocolate.Configuration;
@@ -50,6 +49,7 @@ public static class Interceptors
5049
public static class ExtensionKeys
5150
{
5251
public const string CodeKey = "code";
52+
public const string OperationKey = "operation";
5353
public const string FieldKey = "field";
5454
public const string ArgumentKey = "argument";
5555
public const string PropertyKey = "property";
@@ -107,6 +107,7 @@ public static void Default(IErrorBuilder errorBuilder, ErrorMappingContext mappi
107107
public static void Details(IErrorBuilder errorBuilder, ErrorMappingContext mappingContext)
108108
{
109109
errorBuilder
110+
.SetExtension(ExtensionKeys.OperationKey, mappingContext.MiddlewareContext.Operation.Name?.Value)
110111
.SetExtension(ExtensionKeys.FieldKey, mappingContext.MiddlewareContext.Selection.Field.Name)
111112
.SetExtension(ExtensionKeys.ArgumentKey, mappingContext.Argument.Name)
112113
.SetExtension(ExtensionKeys.PropertyKey, mappingContext.ValidationFailure.PropertyName)

tests/AppAny.HotChocolate.FluentValidation.Tests/Core/TestSetup.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public static ValueTask<IRequestExecutor> CreateRequestExecutor(
2626
public static class Mutations
2727
{
2828
public const string WithEmptyName = "mutation { test(input: { name: \"\" }) }";
29+
30+
public const string MultipleMutationsWithEmptyName =
31+
"mutation { a: test(input: { name: \"\" }), b: test(input: { name: \"\" }) }";
32+
33+
public const string WithOperationNameEmptyName = "mutation OperationName { test(input: { name: \"\" }) }";
2934
public const string WithNullInput = "mutation { test(input: null) }";
3035
public const string WithEmptyNameAndAddress = "mutation { test(input: { name: \"\", address: \"\" }) }";
3136

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System.Threading.Tasks;
2+
using FluentValidation;
3+
using HotChocolate;
4+
using HotChocolate.Execution;
5+
using HotChocolate.Types;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Xunit;
8+
9+
namespace AppAny.HotChocolate.FluentValidation.Tests
10+
{
11+
public class MultipleMutations
12+
{
13+
[Fact]
14+
public async Task Multiple()
15+
{
16+
var executor = await TestSetup.CreateRequestExecutor(builder =>
17+
{
18+
builder.AddFluentValidation(options => options.UseDefaultErrorMapperWithDetails())
19+
.AddMutationType(new TestMutation(field =>
20+
{
21+
field.Argument("input", arg => arg.Type<NonNullType<TestPersonInputType>>().UseFluentValidation());
22+
}));
23+
},
24+
services =>
25+
{
26+
services.AddTransient<IValidator<TestPersonInput>, NotEmptyNameValidator>();
27+
});
28+
29+
var result = Assert.IsType<QueryResult>(
30+
await executor.ExecuteAsync(TestSetup.Mutations.MultipleMutationsWithEmptyName));
31+
32+
Assert.Collection(result.Data!,
33+
data =>
34+
{
35+
Assert.Equal("a", data.Key);
36+
Assert.Null(data.Value);
37+
},
38+
data =>
39+
{
40+
Assert.Equal("b", data.Key);
41+
Assert.Null(data.Value);
42+
});
43+
44+
Assert.Collection(result.Errors!,
45+
error =>
46+
{
47+
Assert.Equal("NotEmptyValidator", error.Code);
48+
Assert.Equal(NotEmptyNameValidator.Message, error.Message);
49+
50+
Assert.Collection(error.Extensions!,
51+
code =>
52+
{
53+
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
54+
Assert.Equal("NotEmptyValidator", code.Value);
55+
},
56+
operation =>
57+
{
58+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
59+
Assert.Null(operation.Value);
60+
},
61+
field =>
62+
{
63+
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
64+
Assert.Equal(new NameString("test"), field.Value);
65+
},
66+
argument =>
67+
{
68+
Assert.Equal(ValidationDefaults.ExtensionKeys.ArgumentKey, argument.Key);
69+
Assert.Equal(new NameString("input"), argument.Value);
70+
},
71+
property =>
72+
{
73+
Assert.Equal(ValidationDefaults.ExtensionKeys.PropertyKey, property.Key);
74+
Assert.Equal("Name", property.Value);
75+
},
76+
severity =>
77+
{
78+
Assert.Equal(ValidationDefaults.ExtensionKeys.SeverityKey, severity.Key);
79+
Assert.Equal(Severity.Error, severity.Value);
80+
});
81+
},
82+
error =>
83+
{
84+
Assert.Equal("NotEmptyValidator", error.Code);
85+
Assert.Equal(NotEmptyNameValidator.Message, error.Message);
86+
87+
Assert.Collection(error.Extensions!,
88+
code =>
89+
{
90+
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
91+
Assert.Equal("NotEmptyValidator", code.Value);
92+
},
93+
operation =>
94+
{
95+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
96+
Assert.Null(operation.Value);
97+
},
98+
field =>
99+
{
100+
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
101+
Assert.Equal(new NameString("test"), field.Value);
102+
},
103+
argument =>
104+
{
105+
Assert.Equal(ValidationDefaults.ExtensionKeys.ArgumentKey, argument.Key);
106+
Assert.Equal(new NameString("input"), argument.Value);
107+
},
108+
property =>
109+
{
110+
Assert.Equal(ValidationDefaults.ExtensionKeys.PropertyKey, property.Key);
111+
Assert.Equal("Name", property.Value);
112+
},
113+
severity =>
114+
{
115+
Assert.Equal(ValidationDefaults.ExtensionKeys.SeverityKey, severity.Key);
116+
Assert.Equal(Severity.Error, severity.Value);
117+
});
118+
});
119+
}
120+
}
121+
}

tests/AppAny.HotChocolate.FluentValidation.Tests/OverrideErrorMappers.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,75 @@ public async Task UseDefaultErrorMapperWithDetails()
125125
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
126126
Assert.Equal("NotEmptyValidator", code.Value);
127127
},
128+
operation =>
129+
{
130+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
131+
Assert.Null(operation.Value);
132+
},
133+
field =>
134+
{
135+
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
136+
Assert.Equal(new NameString("test"), field.Value);
137+
},
138+
argument =>
139+
{
140+
Assert.Equal(ValidationDefaults.ExtensionKeys.ArgumentKey, argument.Key);
141+
Assert.Equal(new NameString("input"), argument.Value);
142+
},
143+
property =>
144+
{
145+
Assert.Equal(ValidationDefaults.ExtensionKeys.PropertyKey, property.Key);
146+
Assert.Equal("Name", property.Value);
147+
},
148+
severity =>
149+
{
150+
Assert.Equal(ValidationDefaults.ExtensionKeys.SeverityKey, severity.Key);
151+
Assert.Equal(Severity.Error, severity.Value);
152+
});
153+
});
154+
}
155+
156+
[Fact]
157+
public async Task UseDefaultErrorMapperWithDetailsWithOperationName()
158+
{
159+
var executor = await TestSetup.CreateRequestExecutor(builder =>
160+
{
161+
builder.AddFluentValidation(opt => opt.UseDefaultErrorMapperWithDetails())
162+
.AddMutationType(new TestMutation(field =>
163+
{
164+
field.Argument("input", arg =>
165+
{
166+
arg.Type<NonNullType<TestPersonInputType>>().UseFluentValidation();
167+
});
168+
}));
169+
},
170+
services =>
171+
{
172+
services.AddTransient<IValidator<TestPersonInput>, NotEmptyNameValidator>();
173+
});
174+
175+
var result = Assert.IsType<QueryResult>(
176+
await executor.ExecuteAsync(TestSetup.Mutations.WithOperationNameEmptyName));
177+
178+
result.AssertNullResult();
179+
180+
Assert.Collection(result.Errors!,
181+
error =>
182+
{
183+
Assert.Equal("NotEmptyValidator", error.Code);
184+
Assert.Equal(NotEmptyNameValidator.Message, error.Message);
185+
186+
Assert.Collection(error.Extensions!,
187+
code =>
188+
{
189+
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
190+
Assert.Equal("NotEmptyValidator", code.Value);
191+
},
192+
operation =>
193+
{
194+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
195+
Assert.Equal("OperationName", operation.Value);
196+
},
128197
field =>
129198
{
130199
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
@@ -184,6 +253,11 @@ public async Task UseDefaultErrorMapperWithExtendedDetails()
184253
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
185254
Assert.Equal("NotEmptyValidator", code.Value);
186255
},
256+
operation =>
257+
{
258+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
259+
Assert.Null(operation.Value);
260+
},
187261
field =>
188262
{
189263
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
@@ -276,6 +350,11 @@ public async Task UseDefaultErrorMapperWithCustomExtendedDetails()
276350
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
277351
Assert.Equal("NotEmptyValidator", code.Value);
278352
},
353+
operation =>
354+
{
355+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
356+
Assert.Null(operation.Value);
357+
},
279358
field =>
280359
{
281360
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
@@ -371,6 +450,11 @@ public async Task MultipleErrorMappers()
371450
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
372451
Assert.Equal("NotEmptyValidator", code.Value);
373452
},
453+
operation =>
454+
{
455+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
456+
Assert.Null(operation.Value);
457+
},
374458
field =>
375459
{
376460
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);

tests/AppAny.HotChocolate.FluentValidation.Tests/OverrideUseFluentValidation.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ public async Task UseDefaultErrorMapperWithDetailsFieldOverride()
7777
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
7878
Assert.Equal("NotEmptyValidator", code.Value);
7979
},
80+
operation =>
81+
{
82+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
83+
Assert.Null(operation.Value);
84+
},
8085
field =>
8186
{
8287
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);

tests/AppAny.HotChocolate.FluentValidation.Tests/UsingAttributes.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ public async Task DefaultErrorMapperWithDetails()
139139
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
140140
Assert.Equal("NotEmptyValidator", code.Value);
141141
},
142+
operation =>
143+
{
144+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
145+
Assert.Null(operation.Value);
146+
},
142147
field =>
143148
{
144149
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);
@@ -192,6 +197,11 @@ public async Task DefaultErrorMapperWithExtendedDetails()
192197
Assert.Equal(ValidationDefaults.ExtensionKeys.CodeKey, code.Key);
193198
Assert.Equal("NotEmptyValidator", code.Value);
194199
},
200+
operation =>
201+
{
202+
Assert.Equal(ValidationDefaults.ExtensionKeys.OperationKey, operation.Key);
203+
Assert.Null(operation.Value);
204+
},
195205
field =>
196206
{
197207
Assert.Equal(ValidationDefaults.ExtensionKeys.FieldKey, field.Key);

0 commit comments

Comments
 (0)