Создание первого минимального 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 — локальная установка не требуется.
Все уроки этого курса
- Создание первого минимального API
- Группы маршрутов, параметры и проверка
- Промежуточное ПО и фильтры в минимальных API
- OpenAPI, версионирование и развёртывание