Skip to content

4. Adding a REST API

You have commands and queries, but no way to reach them over HTTP. The [RestApi] attribute fixes that — handlers you've already decorated with [HttpGet] and [HttpPost] become Minimal API endpoints with generated routing, validation, and OpenAPI docs.

Declare the API

src/Library.Catalog/Runtime.cs (add to existing)
[RestApi(RoutePrefix = "/api/catalog", Title = "Library Catalog API")]
public partial class CatalogRestApi;

The generator scans handlers with HTTP attributes and produces:

  • AddCatalogRestApi() — DI registration (JSON options, CORS, OpenAPI)
  • MapCatalogRestApi() — maps every [HttpGet]/[HttpPost] handler as a Minimal API route

You already decorated your handlers in Chapter 3:

[HttpPost("/books")]      // → POST /api/catalog/books
[HttpGet("/books/search")] // → GET  /api/catalog/books/search

These attributes don't do anything on their own — they're metadata. The [RestApi] generator reads them and produces the endpoint wiring.

Rate Limiting

AddBook already has [RateLimit("default")]. This generates rate-limiting middleware on the endpoint. One attribute, instant protection. The policy name ("default") references a rate-limiting policy you configure in your host — but even before that, the attribute documents intent.

What Gets Generated

The generated REST API code lives in generated/Deepstaging.Web.WebEndpointGenerator/. You'll find:

  • Route registration (app.MapPost("/api/catalog/books", ...))
  • Request deserialization and validation (from the [Required]/[MaxLength] attributes on your command records)
  • Response serialization
  • OpenAPI metadata

Run It

You'll need a host to actually serve HTTP — that comes later when you compose your contexts. For now, the generated code compiles and the endpoints are ready to wire.

dotnet build

No errors? The API surface is defined. You'll see it in action when we compose the full application.

Next → The Lending Context