In ASP.NET Core Minimal APIs, separation of concerns is achieved by moving endpoint definitions from Program.cs into separate feature-specific files using extension methods. This approach improves maintainability as applications grow by grouping related endpoints together and reducing complexity in the main program file.
MapGroup() in ASP.NETIn ASP.NET Core Minimal APIs, the MapGroup() method creates endpoint groups sharing a common URL prefix, reducing repetition and improving organization. Endpoint groups allow related routes to be defined once and applied consistently across multiple endpoints.
// Create a group for book endpointsvar booksGroup = app.MapGroup("/api/books");// Define endpoints within the groupbooksGroup.MapGet("/", () => booksList);booksGroup.MapPost("/", (Book book) => Results.Created($"/api/books/{book.Id}", book));booksGroup.MapGet("/{id}", (int id) => FindBook(id));// Nested group for book reviewsvar reviewsGroup = booksGroup.MapGroup("/{bookId}/reviews");reviewsGroup.MapGet("/", (int bookId) => GetReviews(bookId));
TypedResultsIn ASP.NET Core Minimal APIs, TypedResults provides strongly-typed HTTP responses that enhance API documentation and enable better client code generation. Unlike the regular Results class, TypedResults includes explicit type information that improves compile-time checking and Swagger schema generation
// Using TypedResults with explicit type informationapp.MapGet("/api/books", () => TypedResults.Ok<List<Book>>(books));// Type-safe handling of success and error casesapp.MapGet("/api/books/{id}", (int id) =>{var book = bookList.FirstOrDefault(b => b.Id == id);return book is not null? TypedResults.Ok<Book>(book): TypedResults.NotFound();});// Creating resources with proper status codeapp.MapPost("/api/books", (Book book) =>TypedResults.Created<Book>($"/api/books/{book.Id}", book));
In ASP.NET Core Minimal APIs, parameter binding automatically maps data from HTTP requests to endpoint handler parameters based on parameter names. The framework intelligently determines the binding source without requiring explicit configuration in most cases.
When more control is needed, explicit binding attributes specify exact data sources.
// Automatic bindingapp.MapGet("/api/books/{id}", (int id, string title) =>$"Book ID: {id}, Title filter: {title}");// id binds from route, title from query string// Explicit binding with attributesapp.MapGet("/api/catalog/{category}",([FromRoute] string category,[FromQuery] decimal maxPrice,[FromHeader(Name = "Accept-Language")] string language) =>$"Category: {category}, Max Price: {maxPrice}, Language: {language}");
In ASP.NET Core Minimal APIs, structured error handling returns standardized problem details responses conforming to RFC 7807, providing consistent error reporting across all endpoints. The TypedResults.Problem() method generates these structured JSON responses with predefined fields like type, title, status, and detail.
app.MapGet("/api/books/{id}", (int id) =>{var book = books.FirstOrDefault(b => b.Id == id);if (book == null){return TypedResults.Problem(detail: $"Book with ID {id} not found.",statusCode: StatusCodes.Status404NotFound,title: "Resource Not Found");}return TypedResults.Ok(book);});
In ASP.NET Core Minimal APIs, endpoint filters provide middleware-like capabilities at the endpoint level, enabling cross-cutting concerns like logging, validation, and caching without cluttering handler code. Filters implement the IEndpointFilter interface with pre-processing before and post-processing after endpoint execution.
// Define a filterpublic class LogFilter : IEndpointFilter{public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context,EndpointFilterDelegate next){Console.WriteLine("Request started");var result = await next(context);Console.WriteLine("Request completed");return result;}}// Apply to endpoint or groupapp.MapPost("/api/books", (Book b) => Results.Created($"/api/books/{b.Id}", b)).AddEndpointFilter<LogFilter>();
In ASP.NET Core Minimal APIs, dependency injection simplifies service access by injecting dependencies directly as endpoint handler parameters. This eliminates the need for controller classes with constructor injection, making endpoints more concise.
Services are registered in the DI container during startup and automatically resolved when endpoints are invoked.
// Register services in the DI containerbuilder.Services.AddScoped<BookService>();// Inject service directly in endpoint handlerapp.MapGet("/api/books", (BookService service) =>{var books = service.GetBooks();return Results.Ok(books);});// Combine with route parameters and other bindingsapp.MapGet("/api/books/{id}", (int id, BookService service) =>{var book = service.GetBooks().FirstOrDefault(b => b.Id == id);return book is null ? Results.NotFound() : Results.Ok(book);});
In ASP.NET Core Minimal APIs, security is implemented through authentication middleware and endpoint-specific authorization requirements. The framework provides a fluent API to configure security services during startup and apply authorization rules to individual endpoints or groups.
// Configure authentication and authorizationbuilder.Services.AddAuthentication("Bearer").AddJwtBearer();builder.Services.AddAuthorization();// Apply middleware in the request pipelineapp.UseAuthentication();app.UseAuthorization();// Secure individual endpoint - requires any authenticated userapp.MapGet("/api/books", () => books).RequireAuthorization();// Secure endpoint with role requirementapp.MapDelete("/api/books/{id}", (int id) => DeleteBook(id)).RequireAuthorization(policy => policy.RequireRole("Admin"));// Secure all endpoints in a groupvar secureGroup = app.MapGroup("/api/admin").RequireAuthorization();