> For the complete documentation index, see [llms.txt](https://framework.aic.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://framework.aic.io/technical-guidelines-code-standards-and-tech-stack/tech-stack/web-api-stack.md).

# Web API Stack

## AIC Standard

ASP.NET Core on .NET 10 is the AIC default for Web API delivery.

Use Minimal APIs for simple, focused HTTP APIs and microservice endpoints. Use controllers where the API benefits from richer conventions, filters, versioning patterns, complex model binding, or larger team familiarity.

## Required Components

A production Web API SHOULD include:

* clear endpoint structure
* request and response DTOs
* validation layer
* ProblemDetails error responses
* authentication and authorization
* OpenAPI documentation
* structured logging
* correlation identifier
* health checks
* metrics and traces
* integration tests
* security tests for access control
* versioning strategy
* configuration validation
* rate limiting or throttling where needed
* resilience policies for downstream calls

## Recommended Project Structure

```
src/
  Aic.Product.Api/
  Aic.Product.Application/
  Aic.Product.Domain/
  Aic.Product.Infrastructure/
tests/
  Aic.Product.Api.Tests/
  Aic.Product.Application.Tests/
  Aic.Product.IntegrationTests/
```

## Minimal API Example

```csharp
app.MapGet("/v1/cases/{caseId:guid}", async (
    Guid caseId,
    ICaseQueries queries,
    CancellationToken cancellationToken) =>
{
    var result = await queries.GetCaseAsync(caseId, cancellationToken);
    return result is null ? Results.NotFound() : Results.Ok(result);
})
.RequireAuthorization("Cases.Read")
.WithName("GetCase")
.WithOpenApi();
```

## Controller Example

```csharp
[ApiController]
[Route("api/v{version:apiVersion}/cases")]
[Authorize(Policy = "Cases.Read")]
public sealed class CasesController : ControllerBase
{
    private readonly ICaseQueries _queries;

    public CasesController(ICaseQueries queries)
    {
        _queries = queries;
    }

    [HttpGet("{caseId:guid}")]
    [ProducesResponseType<CaseResponse>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<CaseResponse>> GetCase(
        Guid caseId,
        CancellationToken cancellationToken)
    {
        var result = await _queries.GetCaseAsync(caseId, cancellationToken);
        return result is null ? NotFound() : Ok(result);
    }
}
```

## API Quality Gate

Before an API is released:

* OpenAPI document is generated
* authentication behaviour is tested
* authorization policies are tested
* validation failures return consistent errors
* 401, 403, 404, 409 and 500 behaviours are understood
* logs contain correlation identifiers
* health checks exist
* dependency timeouts are configured
* integration tests pass
* backward compatibility is reviewed
