0Pricing
C# Academy · Урок

Создание первого минимального API

Создайте проект минимального API, определите обработчики маршрутов и возвращайте типизированные результаты с минимумом шаблонного кода.

«Создание первого минимального API» — бесплатный урок C# Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Что такое минимальные API

Минимальные API, появившиеся в .NET 6, позволяют создавать конечные точки HTTP с минимальным количеством обвязки — без контроллеров и атрибутов действий, только с обработчиками маршрутов, определёнными непосредственно в Program.cs. Они идеально подходят для микросервисов и лёгких API.

Самое простое минимальное API

Полное HTTP API всего в нескольких строках. Методы MapGet, MapPost, MapPut и MapDelete определяют обработчики маршрутов для каждого метода HTTP.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello, Minimal API!");
app.MapGet("/ping", () => Results.Ok(new { status = "pong" }));

app.Run();
// That's it — no Startup.cs, no controllers

Типизированные результаты для корректных ответов HTTP

Используйте Results или TypedResults для корректных кодов состояния HTTP и типов содержимого. TypedResults предпочтительнее для вывода схемы OpenAPI.

app.MapGet("/products/{id}", async (int id, AppDbContext db) =>
{
    var product = await db.Products.FindAsync(id);
    return product is null
        ? Results.NotFound()
        : Results.Ok(product);
});

app.MapPost("/products", async (Product product, AppDbContext db) =>
{
    db.Products.Add(product);
    await db.SaveChangesAsync();
    return Results.Created($"/products/{product.Id}", product);
});

Параметры маршрута и строки запроса

Параметры маршрута извлекаются из пути URL, параметры строки запроса автоматически связываются с данными запроса, а тело запроса десериализуется из JSON.

// Route param {id} + query param ?includeDeleted
app.MapGet("/orders/{id}", async (
    int id,
    bool includeDeleted = false,
    AppDbContext db) =>
{
    var query = db.Orders.AsQueryable();
    if (!includeDeleted) query = query.Where(o => !o.IsDeleted);
    var order = await query.FirstOrDefaultAsync(o => o.Id == id);
    return order is null ? Results.NotFound() : Results.Ok(order);
});

Внедрение зависимостей в обработчики маршрутов

Сервисы, зарегистрированные в контейнере DI, можно напрямую внедрять как параметры обработчика маршрута. Платформа разрешает их автоматически.

builder.Services.AddScoped<ProductService>();

app.MapGet("/products", async (ProductService svc) =>
{
    var products = await svc.GetAllAsync();
    return Results.Ok(products);
});

app.MapDelete("/products/{id}", async (int id, ProductService svc) =>
{
    var deleted = await svc.DeleteAsync(id);
    return deleted ? Results.NoContent() : Results.NotFound();
});

Связывание тела запроса

Параметры, соответствующие зарегистрированным сервисам, внедряются; всё остальное связывается с телом запроса (по умолчанию в формате JSON). При необходимости явно используйте [FromBody].

record CreateProductRequest(string Name, decimal Price, int Stock);

app.MapPost("/products", async (
    CreateProductRequest req,
    ProductService svc) =>
{
    var product = await svc.CreateAsync(req.Name, req.Price, req.Stock);
    return TypedResults.Created($"/products/{product.Id}", product);
});

Возврат разных кодов состояния

Results предоставляет фабричные методы для всех распространённых ответов HTTP. Используйте их для семантически корректных REST API.

app.MapPut("/products/{id}", async (int id, Product update, AppDbContext db) =>
{
    var existing = await db.Products.FindAsync(id);
    if (existing is null) return Results.NotFound();

    existing.Name  = update.Name;
    existing.Price = update.Price;
    await db.SaveChangesAsync();
    return Results.Ok(existing);
});

// Other useful Results:
// Results.BadRequest("message")
// Results.Conflict()
// Results.UnprocessableEntity(errors)
// Results.Accepted()

Добавление метаданных с помощью WithName и WithTags

Добавляйте к конечным точкам метаданные, чтобы улучшить документацию и маршрутизацию. Используйте WithName, WithTags и WithSummary для структурированного вывода OpenAPI.

app.MapGet("/products/{id}", GetProduct)
   .WithName("GetProductById")
   .WithTags("Products")
   .WithSummary("Retrieves a product by its ID")
   .Produces<Product>()
   .Produces(404);

static async Task<IResult> GetProduct(int id, AppDbContext db)
{
    var p = await db.Products.FindAsync(id);
    return p is null ? Results.NotFound() : Results.Ok(p);
}

Авторизация в минимальных API

Применяйте RequireAuthorization() для защиты конечных точек или используйте AllowAnonymous(), чтобы разрешить доступ без авторизации. Политики работают так же, как и в контроллерах.

builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();

app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/profile", (ClaimsPrincipal user) =>
    Results.Ok(user.Identity!.Name))
   .RequireAuthorization();

app.MapGet("/public", () => "No auth needed")
   .AllowAnonymous();

Организация с помощью статических методов

Для более крупных API перенесите обработчики маршрутов в статические методы или методы расширения, чтобы Program.cs оставался чистым и удобным для навигации.

// Extension method groups endpoints by feature
public static class ProductEndpoints
{
    public static void MapProductEndpoints(this WebApplication app)
    {
        app.MapGet("/products",    GetAll);
        app.MapGet("/products/{id}", GetById);
        app.MapPost("/products",   Create);
    }

    private static async Task<IResult> GetAll(AppDbContext db)
        => Results.Ok(await db.Products.AsNoTracking().ToListAsync());

    // ... other handlers
}

// In Program.cs:
app.MapProductEndpoints();

Практический пример: полный CRUD для минимального API

Полный минимальный CRUD API для ресурса задач — краткий, пригодный для тестирования и готовый к промышленной эксплуатации.

app.MapGet("/todos", async (AppDbContext db) =>
    Results.Ok(await db.Todos.AsNoTracking().ToListAsync()));

app.MapGet("/todos/{id}", async (int id, AppDbContext db) =>
{
    var todo = await db.Todos.FindAsync(id);
    return todo is null ? Results.NotFound() : Results.Ok(todo);
});

app.MapPost("/todos", async (Todo todo, AppDbContext db) =>
{
    db.Todos.Add(todo);
    await db.SaveChangesAsync();
    return Results.Created($"/todos/{todo.Id}", todo);
});

app.MapDelete("/todos/{id}", async (int id, AppDbContext db) =>
{
    int n = await db.Todos.Where(t => t.Id == id).ExecuteDeleteAsync();
    return n > 0 ? Results.NoContent() : Results.NotFound();
});

Быстрая проверка

Как обработчик маршрута минимального API получает зарегистрированную службу DI?

Итоги: создание первого минимального API

Основные выводы:

  • MapGet/Post/Put/Delete напрямую определяют обработчики маршрутов в Program.cs
  • Используйте Results / TypedResults для правильных кодов состояния HTTP
  • Параметры маршрута, строки запроса, тела запроса и DI связываются автоматически
  • Используйте RequireAuthorization() и AllowAnonymous() для аутентификации
  • Организуйте крупные API с помощью методов расширения или групп маршрутов

Часто задаваемые вопросы

Урок «Создание первого минимального API» бесплатный?

Да — полный текст урока «Создание первого минимального API» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Создание первого минимального API»?

Создайте проект минимального API, определите обработчики маршрутов и возвращайте типизированные результаты с минимумом шаблонного кода. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Создание первого минимального API»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Создание первого минимального API
  2. Группы маршрутов, параметры и проверка
  3. Промежуточное ПО и фильтры в минимальных API
  4. OpenAPI, версионирование и развёртывание
← Назад к C# Academy