TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2334 2.7K
День 1930. #ЗаметкиНаПолях
Организуем Минимальные API в
ASP.NET Core
Часто говорят, что нельзя использовать минимальные API для «реальных» приложений. Скорее всего, причина в том, что большинство примеров очень просты и не показывают, как организовать код так, чтобы это имело смысл для более крупного приложения.

Проблема в том, что в ASP.NET все примеры заканчиваются некоторыми конечными точками в Program.cs со встроенным кодом (как показано ниже), и на самом деле это не то, каким вы хотите видеть код в более крупном приложении:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
…
app.MapGet("/todos", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todos/{id}",
async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
…
app.Run();

Здесь мы используем пример из руководства Microsoft. Итак, рассмотрим, как организовать код в что-то более удобочитаемое.

1. Используем методы расширения для организации конечных точек
В папке Endpoints или Todos (если вы используете чистую архитектуру) создадим файл TodoEndpoints.cs:
public static class TodoEndpoints
{
public static void
RegisterTodoEndpoints(this WebApplication app)
{
app.MapGet("/todos", async (TodoDb db) =>
await db.Todos.ToListAsync());

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

Это сразу сделает файл Program.cs намного чище:
…
var app = builder.Build();
…
app.RegisterTodosEndpoints();
app.Run();

Также мы можем разделить группы конечных точек по файлам.

2. Используем TypedResults вместо Results
TypedResults позволит нам не использовать атрибут или метод Produces для описания типа возвращаемого значения для OpenAPI/Swagger. Тип будет выведен из типа возвращаемого значения:
app.MapGet("/todos/{id}", 
async Task<Results<Ok<Todo>, NotFound>> (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound());


3. Отделим функциональность от регистрации
Лямбда–выражение из метода конечной точки можно вынести в отдельный метод, что улучшит читаемость и тестируемость:
app.MapGet("/todos/{id}", GetById);

static async Task<Results<Ok<Todo>, NotFound>>
GetById(int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();

Тогда регистрация TodoEndpoints будет выглядеть так:
app.MapGet("/todos", GetAll);
app.MapGet("/todos/{id}", GetById);
…
// методы

Теперь в тестах методы можно вызывать напрямую, а не через API.

4. Группируем
Конечные точки можно сгруппировать, чтобы избежать повторения кода:
var todos = app.MapGroup("/todos");

todos.MapGet("/", GetAll);
todos.MapGet("/{id}", GetById);
…

Также к группе можно применять общие политики, тэги и т.п.
var todos = app.MapGroup("/todos")
.RequireAuthorization()
.WithTags("Todos");

Источник: https://www.tessferrandez.com/blog/2023/10/31/organizing-minimal-apis.html
  • 👍 43
  • 👎 1
More from @netdeveloperdiary
  1. Oct 7, 2026День 2807. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Окончание Нач…
  2. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  3. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
  4. Oct 5, 2026День 2805. #ЧтоНовенького #NET11 Аргументы в Выражениях Коллекций в C#15 В C#15 реализован…
  5. Oct 4, 2026День 2804. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  6. Oct 3, 2026Post #3360
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →