Организуем Минимальные 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