Interview question
Return consistent validation ProblemDetails
Produces field-keyed validation errors through one reusable endpoint boundary.
TL;DR
Produces field-keyed validation errors through one reusable endpoint boundary.
Endpoint filters, field keys, ProblemDetails, reusable validation, and contract stability.
Practice the problem like a real interview: restate, reason, implement, and test.
Validate CreateUserRequest before the handler runs. Return RFC-style validation details keyed by public DTO fields; do not return exception messages or validator internals.
A blank display name and malformed email return one 400 response containing displayName and email arrays.
I make validation an endpoint boundary so handlers receive structurally valid input. The validator returns a dictionary rather than throwing, and the filter maps that dictionary directly to ValidationProblem.
public interface IRequestValidator<T>
{
Dictionary<string, string[]> Validate(T request);
}
public sealed class ValidationFilter<T>(IRequestValidator<T> validator)
: IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
var request = context.Arguments.OfType<T>().Single();
var errors = validator.Validate(request);
return errors.Count == 0
? await next(context)
: TypedResults.ValidationProblem(errors);
}
}
var users = app.MapGroup("/users");
users.MapPost("/", CreateUser)
.AddEndpointFilter<ValidationFilter<CreateUserRequest>>();
The filter removes repeated plumbing without turning domain failures into validation. If endpoints need different rule sets, register explicit validators rather than hiding conditional behavior in one global validator.
Next in Contracts & Inputs: Safe List Query