S

super-dev — full-stack

@super-dev.app · Full-stack · ★ disponible para proyectos
12,8k suscriptores·47 vídeos·Activo desde 2017

Desarrollador full-stack .NET / Angular con perfil DevOps en Azure Cloud. También cómodo con Flutter + Firebase. Construyo productos, los despliego, los monitorizo.

Volver a los artículos
ƒ()
.NET
.NET

Minimal APIs + EF Core: una API .NET 8 limpia

Artículo 2 de 5 — El .NET moderno
APIs mínimas, CQRS, gRPC, source generators: .NET 8 limpio y testeable, sin complicaciones.

Las Minimal APIs tienen mala reputación: se las cree reservadas a demos desechables. En realidad, con un poco de disciplina, ofrecen una API .NET 8 más legible y más testeable que un controlador clásico — siempre que no se amontone todo en Program.cs .

Estructurar con route groups

La trampa del principiante es apilar treinta app.MapGet en el Program.cs . La solución se resume en una palabra: `MapGroup` . Cada recurso tiene su grupo, con su prefijo, sus filtros y sus metadatos, definido en un método de extensión dedicado:

C#
1public static class TodoEndpoints
2{
3 public static RouteGroupBuilder MapTodos(this IEndpointRouteBuilder app)
4 {
5 var group = app.MapGroup("/todos")
6 .WithTags("Todos")
7 .WithOpenApi();
8
9 group.MapGet("/", GetAllAsync);
10 group.MapGet("/{id:int}", GetByIdAsync);
11 group.MapPost("/", CreateAsync);
12
13 return group;
14 }
15
16 private static async Task<Ok<List<Todo>>> GetAllAsync(AppDbContext db) =>
17 TypedResults.Ok(await db.Todos.AsNoTracking().ToListAsync());
18}

El Program.cs se reduce entonces a app.MapTodos(); — un punto de entrada por recurso, el resto vive en archivos coherentes.

DbContext y migraciones

EF Core sigue siendo la columna vertebral del acceso a datos. Se registra el DbContext mediante AddDbContext , se modela en OnModelCreating , y sobre todo nunca se deja que el esquema derive manualmente: cada cambio pasa por una migración versionada.

C#
1builder.Services.AddDbContext<AppDbContext>(options =>
2 options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));

Luego se genera la migración con dotnet ef migrations add InitialCreate , y se aplica al arranque con db.Database.MigrateAsync() — nunca EnsureCreated , que cortocircuita todo el historial. La documentación oficial detalla el flujo de trabajo en la guía de migraciones de EF Core .

Resultados tipados y validación

Aquí es donde las Minimal APIs realmente ganan terreno. En lugar de devolver un IActionResult opaco, se retorna una unión de resultados tipados : la firma documenta los códigos HTTP posibles, y OpenAPI los expone automáticamente.

C#
1private static async Task<Results<Created<Todo>, ValidationProblem>> CreateAsync(
2 CreateTodoRequest request, AppDbContext db)
3{
4 if (string.IsNullOrWhiteSpace(request.Title))
5 {
6 return TypedResults.ValidationProblem(new Dictionary<string, string[]>
7 {
8 ["title"] = ["Le titre est obligatoire."],
9 });
10 }
11
12 var todo = new Todo { Title = request.Title };
13
14 db.Todos.Add(todo);
15 await db.SaveChangesAsync();
16
17 return TypedResults.Created($"/todos/{todo.Id}", todo);
18}

El tipo de retorno Results<Created<Todo>, ValidationProblem> es autodocumentado : no hacen falta atributos [ProducesResponseType] redundantes.

Mantener todo testeable

Una vez que los handlers se extraen en métodos estáticos que reciben sus dependencias como parámetros, se vuelven triviales de testear sin servidor HTTP : se instancia un AppDbContext sobre el proveedor in-memory o SQLite, se llama al handler y se inspecciona el TypedResults . Para los tests de integración de extremo a extremo, WebApplicationFactory<T> levanta la aplicación completa en memoria y permite invocar los endpoints reales.

Una Minimal API no es una API de segunda categoría. Bien estructurada en grupos y en resultados tipados, expone menos ceremonia para más garantías — y eso es exactamente lo que se espera de un framework moderno.
super-dev — portfolio.app
// Continuar en .NET
{ }
Estrangular un monolito .NET 8 sin romper nada
9 min • 3,2k lecturas
CQRS y vertical slices sin sobreingeniería
7 min • 2,3k lecturas
gRPC entre microservicios .NET
9 min • 1,8k lecturas