# ASP.Net Core: Routing - Minimal API

### 1\. Basic Explicit Mapping (The Foundation)

In Minimal APIs, every route is mapped explicitly using extension methods on the `WebApplication` (`app`) object. There is no auto-discovery by default.

* **Standard HTTP Verbs:** Mapping is done by calling the method corresponding to the HTTP verb.
    
    ```csharp
    // GET: /api/hello
    app.MapGet("/api/hello", () => "Hello World");
    
    // POST: /api/users
    app.MapPost("/api/users", (UserDto user) => {
        // Save user logic...
        return Results.Created($"/api/users/{user.Id}", user);
    });
    
    // PUT: /api/users/1
    app.MapPut("/api/users/{id}", (int id, UserDto user) => { ... });
    
    // DELETE: /api/users/1
    app.MapDelete("/api/users/{id}", (int id) => { ... });
    ```
    
* **Handler Types:** You can map a route to a lambda (inline function) or a method reference.
    
    ```csharp
    // Option A: Inline Lambda (Good for simple logic)
    app.MapGet("/inline", () => "Inline");
    
    // Option B: Method Reference (Cleaner)
    string LocalFunction() => "Local Function";
    app.MapGet("/method", LocalFunction);
    ```
    

### 2\. Route Parameters & Constraints

Just like Controllers, Minimal APIs support capturing values from the URL and enforcing data types.

* **Simple Parameters:** The parameter name in the lambda must match the route segment `{...}`.
    
    ```csharp
    // URL: /users/5
    app.MapGet("/users/{id}", (int id) => $"User ID: {id}");
    ```
    
* **Constraints (Data Type Enforcement):** Use `:` to enforce rules. If the rule fails, the API returns `404 Not Found`.
    
    ```csharp
    // Matches: /products/10 (int)
    // Skips: /products/abc
    app.MapGet("/products/{id:int}", (int id) => ...);
    
    // Matches strings with min length 3
    app.MapGet("/search/{query:minlength(3)}", (string query) => ...);
    ```
    
* **Catch-All (Wildcards):** Use `{*name}` to capture the rest of the URL path.
    
    ```csharp
    // Matches: /files/images/logo.png
    // path = "images/logo.png"
    app.MapGet("/files/{*path}", (string path) => ...);
    ```
    

### 3\. Route Groups (Essential for Organization)

Instead of repeating the same prefix `/api/users` for every route, use **Route Groups**. This also allows you to apply middleware (like Authentication) to a whole batch of endpoints at once.

```csharp
// 1. Create a Group
var userGroup = app.MapGroup("/api/users");

// 2. Map routes relative to the group
// Final URL: /api/users
userGroup.MapGet("/", GetUsers);

// Final URL: /api/users/{id}
userGroup.MapGet("/{id}", GetUserById);

// 3. Apply Security to the WHOLE group
userGroup.RequireAuthorization();
```

### 4\. Advanced Parameter Binding

Sometimes you need to tell [ASP.NET](http://ASP.NET) exactly *where* to look for data (Body, Query, Header), rather than letting it guess.

```csharp
using Microsoft.AspNetCore.Mvc; // Required for these attributes

app.MapPost("/orders/{id}", (
    [FromRoute] int id, 
    [FromBody] OrderDto order, 
    [FromQuery] int page, 
    [FromHeader(Name = "X-Request-ID")] string requestId
) => {
    return $"Order {id}, Page {page}, Request {requestId}";
});
```

### 5\. Industry Standard: The "Module" Pattern (Real World)

**Problem:** In a real app with 500+ endpoints, `Program.cs` becomes massive and unreadable if you list all `app.MapGet` calls there.

**Solution:** Use the **Carter** library or a custom **Module Interface** to split routes into separate files (Feature Slices).

### The Carter Library Approach (Industry Favorite)

This achieves the exact same result but removes the need for writing the `EndpointExtensions.cs` file manually. It is battle-tested and supports advanced features like validation pipelines.

**Install:** `dotnet add package Carter`

#### 1\. The Feature Module (`/Features/Products/GetProducts/GetProductsEndpoint.cs`)

Inherit from `ICarterModule` instead of a custom interface.

```csharp
using Carter;
using Microsoft.AspNetCore.Mvc;

namespace MyApi.Features.Products.GetProducts;

public class GetProductsEndpoint : ICarterModule
{
    public void AddRoutes(IEndpointRouteBuilder app)
    {
        var group = app.MapGroup("/api/products");

        group.MapGet("/", HandleAsync)
             .WithName("GetProducts")
             .WithOpenApi();
    }

    internal async Task<IResult> HandleAsync(ILogger<GetProductsEndpoint> logger)
    {
        logger.LogInformation("Fetching products...");
        
        var data = new[] { "Laptop", "Mouse", "Keyboard" };
        return Results.Ok(data);
    }
}
```

#### 2\. The Wiring (`Program.cs`)

It's even shorter.

```csharp
using Carter; // Import the library

var builder = WebApplication.CreateBuilder(args);

// 1. Add Carter to DI
builder.Services.AddCarter(); 
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// 2. Map Carter (Auto-scans and maps all ICarterModules)
app.MapCarter(); 

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.Run();
```
