Skip to main content

Exercise 4: Route Groups & Filters

Objective

Use ASP.NET Core 7+ features: Route Groups and Endpoint Filters.

Route Groups Implementation

var api = app.MapGroup("/api")
.WithOpenApi();

var products = api.MapGroup("/products")
.WithTags("Products")
.AddEndpointFilter(async (context, next) =>
{
// Logging filter for all product endpoints
Console.WriteLine($"Product endpoint called: {context.HttpContext.Request.Path}");
return await next(context);
});

products.MapGet("/", GetAllProducts);
products.MapGet("/{id:int}", GetProduct);
products.MapPost("/", CreateProduct);
products.MapPut("/{id:int}", UpdateProduct);
products.MapDelete("/{id:int}", DeleteProduct);

Endpoint Filters

Validation Filter

app.MapPost("/api/products", CreateProduct)
.AddEndpointFilter(async (context, next) =>
{
var product = context.GetArgument<Product>(0);

if (string.IsNullOrWhiteSpace(product.Name))
return Results.BadRequest("Name is required");

if (product.Price <= 0)
return Results.BadRequest("Price must be positive");

return await next(context);
});

ID Validation Filter

app.MapGet("/api/products/{id:int}", GetProduct)
.AddEndpointFilter(async (context, next) =>
{
var id = context.GetArgument<int>(0);

if (id <= 0)
return Results.BadRequest("Invalid ID");

return await next(context);
});

Rate Limiting with Route Groups

builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("api-limit", opt =>
{
opt.Window = TimeSpan.FromMinutes(1);
opt.PermitLimit = 10;
});
});

var rateLimitedApi = app.MapGroup("/api")
.RequireRateLimiting("api-limit");

Challenge

  1. Create separate route groups for public and authenticated endpoints
  2. Add caching filter for GET requests
  3. Implement audit logging filter
  4. Add response transformation filter

Expected Outcome

  • Well-organized endpoints using route groups
  • Reusable endpoint filters
  • Understanding of filter execution order