Minimal API'de Validation'ı Nereye Koymalı
Filter, endpoint ve DataAnnotations üçgeni

Controller'da [ApiController] validation'ı gizler. Minimal API'de gizlemez. Body bind olur, DataAnnotations durur, istek yine handler'a girer. Null kontrolünü her endpoint'te kopyalamak iki haftada dağılır.
Filter tek kapı
Endpoint filter, bind edilmiş modeli IValidatableObject veya DataAnnotations ile tarar. Hata varsa ProblemDetails 400 döner, handler çalışmaz. Bu, iş kuralını handler'da, şekil kontrolünü filter'da tutar.
public sealed class ValidationFilter : IEndpointFilter where T : class
{
public async ValueTask InvokeAsync(EndpointFilterInvocationContext ctx, EndpointFilterDelegate next)
{
var model = ctx.Arguments.OfType().FirstOrDefault();
if (model is null)
return TypedResults.Problem("Gövde okunamadı.", statusCode: 400);
var results = new List();
if (!Validator.TryValidateObject(model, new ValidationContext(model), results, true))
{
var errors = results
.GroupBy(r => r.MemberNames.FirstOrDefault() ?? "body")
.ToDictionary(g => g.Key, g => g.Select(r => r.ErrorMessage ?? "Geçersiz.").ToArray());
return TypedResults.ValidationProblem(errors);
}
return await next(ctx);
}
}
app.MapPost("/articles", (CreateArticleRequest body) => Results.Created($"/articles/{body.Title}", body))
.AddEndpointFilter>();
FluentValidation de durabilir. Önemli olan doğrulamanın handler'ın içinde if zinciri olmaması. Handler 'bu başlıkla taslak aç' der, 'başlık 300 karakteri aşmasın' demez.
İş kuralı ayrı
Aynı başlığın yazarda unique olması validation değil, domain kuralı. Bunu filter'da DB'ye sorarak yapmak filter'ı servise çevirir. 409'u handler veya application servisi üretir. 400 şekil, 409 durum. Karışınca client neyi düzelteceğini bilemez.
Minimal API sade diye kontrolü silmiyorum. Sade olan handler. Kapı hâlâ duruyor.
Yorumlar
Yorumlar (0)
Yorumlar üyelere açık. Üye ol · Giriş yap