Minimal API — MapGet/Post, endpoint filter, GroupRouteBuilder
Muammodan boshlaylik
Kichik mikroservis — 4 ta endpoint. Controller yondashuvida: controller klassi, atributlar, ControllerBase, [ApiController], AddControllers, MapControllers... Oddiy "ID bo'yicha qaytar" uchun ko'p "marosim". Yangi boshlovchi uchun esa birinchi API dan oldin ko'p tushuncha.
Minimal API nima?
.NET 6 dan boshlab — endpoint larni to'g'ridan-to'g'ri Program.cs da, lambda yoki metod bilan e'lon qilish:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/salom", () => "Salom, dunyo!");
app.Run();
To'rt qator — ishlaydigan API.
Hayotiy o'xshatma
Katta restoran va ko'cha oshxonasi. Restoranda (controller) — qabulxona, ofitsiantlar, menyu kitobi, alohida zallar: katta oqim uchun tartib. Ko'cha oshxonasida (Minimal API) — bitta oyna: buyurtma berding, oldingga berildi. Taom sifati bir xil bo'lishi mumkin — farq tashkiliy tuzilmada. Va ko'cha oshxonasi ham kengayib, bir nechta oynali bo'lishi mumkin (MapGroup).
Asosiy metodlar
app.MapGet("/api/mahsulotlar", async (DokonDbContext db, CancellationToken ct) =>
await db.Mahsulotlar.AsNoTracking().Select(m => new MahsulotDto(m.Id, m.Nomi, m.Narx)).ToListAsync(ct));
app.MapGet("/api/mahsulotlar/{id:int}", async (int id, DokonDbContext db, CancellationToken ct) =>
await db.Mahsulotlar.FindAsync([id], ct) is { } m
? Results.Ok(new MahsulotDto(m.Id, m.Nomi, m.Narx))
: Results.NotFound());
app.MapPost("/api/mahsulotlar", async (MahsulotYaratDto dto, DokonDbContext db, CancellationToken ct) =>
{
var m = new Mahsulot { Nomi = dto.Nomi, Narx = dto.Narx };
db.Mahsulotlar.Add(m);
await db.SaveChangesAsync(ct);
return Results.Created(quot;/api/mahsulotlar/{m.Id}", new MahsulotDto(m.Id, m.Nomi, m.Narx));
});
app.MapPut("/api/mahsulotlar/{id:int}", ...);
app.MapDelete("/api/mahsulotlar/{id:int}", ...);
Parametrlar qayerdan keladi
| Manba | Avtomatik | Aniq |
|---|---|---|
Route {id} |
nomi mos kelsa | [FromRoute] |
Query ?sahifa=2 |
oddiy turlar | [FromQuery] |
| Body (JSON) | murakkab tur | [FromBody] |
| Sarlavha | — | [FromHeader] |
| DI servis | ro'yxatdan o'tgan tur | [FromServices] |
| Maxsus | HttpContext, CancellationToken, ClaimsPrincipal |
— |
Bir nechta parametr — [AsParameters]
public record MahsulotSorov(string? Qidiruv, int Sahifa = 1, int Hajm = 20);
app.MapGet("/api/mahsulotlar", async ([AsParameters] MahsulotSorov s, DokonDbContext db) => ...);
TypedResults — turi aniq javoblar
app.MapGet("/api/mahsulotlar/{id:int}",
async Task<Results<Ok<MahsulotDto>, NotFound>> (int id, DokonDbContext db, CancellationToken ct) =>
{
var m = await db.Mahsulotlar.FindAsync([id], ct);
return m is null ? TypedResults.NotFound() : TypedResults.Ok(new MahsulotDto(m.Id, m.Nomi, m.Narx));
});
Results<Ok<T>, NotFound> — OpenAPI hujjatiga barcha mumkin bo'lgan javoblar avtomatik tushadi (72-dars), unit testda ham turini tekshirish oson.
MapGroup — guruhlash
var mahsulotlar = app.MapGroup("/api/mahsulotlar")
.WithTags("Mahsulotlar")
.RequireAuthorization();
mahsulotlar.MapGet("/", Royxat).AllowAnonymous();
mahsulotlar.MapGet("/{id:int}", Ol).AllowAnonymous();
mahsulotlar.MapPost("/", Yarat).RequireAuthorization("MahsulotBoshqarish");
mahsulotlar.MapDelete("/{id:int}", Ochir).RequireAuthorization("MahsulotBoshqarish");
Umumiy prefiks, teg, avtorizatsiya, rate limit, CORS — bir joyda.
Program.cs ni tartibli saqlash
public static class MahsulotEndpointlari
{
public static RouteGroupBuilder MapMahsulotlar(this IEndpointRouteBuilder app)
{
var g = app.MapGroup("/api/mahsulotlar").WithTags("Mahsulotlar");
g.MapGet("/", Royxat);
g.MapGet("/{id:int}", Ol).WithName("MahsulotOl");
g.MapPost("/", Yarat);
return g;
}
static async Task<Ok<List<MahsulotDto>>> Royxat(MahsulotService s, CancellationToken ct) =>
TypedResults.Ok(await s.RoyxatAsync(ct));
static async Task<Results<Ok<MahsulotDto>, NotFound>> Ol(int id, MahsulotService s, CancellationToken ct) =>
await s.OlAsync(id, ct) is { } m ? TypedResults.Ok(m) : TypedResults.NotFound();
static async Task<Created<MahsulotDto>> Yarat(MahsulotYaratDto dto, MahsulotService s, CancellationToken ct)
{
var m = await s.YaratAsync(dto, ct);
return TypedResults.Created(quot;/api/mahsulotlar/{m.Id}", m);
}
}
// Program.cs
app.MapMahsulotlar();
app.MapBuyurtmalar();
Endpoint filter — "middleware" endpoint uchun
public class ValidatsiyaFilter<T>(IValidator<T> validator) : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext ctx, EndpointFilterDelegate next)
{
var arg = ctx.Arguments.OfType<T>().FirstOrDefault();
if (arg is null) return TypedResults.BadRequest();
var natija = await validator.ValidateAsync(arg);
if (!natija.IsValid)
return TypedResults.ValidationProblem(natija.ToDictionary());
return await next(ctx);
}
}
mahsulotlar.MapPost("/", Yarat).AddEndpointFilter<ValidatsiyaFilter<MahsulotYaratDto>>();
Filter — endpoint dan oldin va keyin ishlaydi: validatsiya, log, vaqtni o'lchash. Guruhga qo'shilsa — guruhdagi hammasiga.
[!INFO] .NET 10 da Minimal API uchun o'rnatilgan validatsiya qo'shilgan:
builder.Services.AddValidation();— DataAnnotations atributlari ([Required],[Range]) bilan belgilangan parametrlar avtomatik tekshiriladi va 400 ProblemDetails qaytariladi.
Controller yoki Minimal API?
| Controller | Minimal API | |
|---|---|---|
| Kod hajmi | Ko'proq | Kam |
| Performance | Yaxshi | Biroz tezroq, Native AOT bilan mos |
| Tuzilma | Konvensiyalar tayyor | O'zingiz tashkil qilasiz (MapGroup, kengaytmalar) |
| Filterlar | Action/Result filter lar | Endpoint filter lar |
| Model binding | Juda boy | Yetarli, ba'zi farqlar bilan |
Microsoft yangi loyihalar uchun Minimal API ni tavsiya qiladi, lekin Controller lar to'liq qo'llab-quvvatlanadi. Ikkalasi bitta loyihada birga ishlaydi. Katta, mavjud jamoaviy loyihada — jamoa konvensiyasi muhimroq.
Tez-tez uchraydigan xatolar
Hammasi Program.cs da — 800 qatorlik fayl; kengaytma metodlar va MapGroup ga ajrating.
Results.Ok(entity) — entity to'g'ridan-to'g'ri; DTO (45-dars).
Results va TypedResults aralash — hujjatda javob turlari yo'qoladi; TypedResults ni afzal ko'ring.
Xulosa
Minimal API — endpoint lar MapGet/MapPost/MapPut/MapDelete bilan, lambda yoki metod orqali; parametrlar route, query, body va DI dan avtomatik. TypedResults + Results<A, B> — turi aniq javoblar, OpenAPI uchun avtomatik.
MapGroup — umumiy prefiks, teg, avtorizatsiya; kengaytma metodlar bilan Program.cs tartibli. Endpoint filter (IEndpointFilter) — validatsiya va kesishuvchi mantiq. Controller va Minimal API — ikkalasi to'liq yechim, birga ishlatish mumkin.
Keyingi bo'lim
76-dars: Unit Test — xUnit, Fact, Theory, Assert