What it is
FastEndpoints is a REST API framework for .NET built on minimal APIs, using the REPR pattern — one class per endpoint with its own request and response types.
Derive from Endpoint<TRequest, TResponse>, configure the route in Configure(), and implement HandleAsync. Validation and DI are wired in automatically.
Installation
dotnet add package FastEndpointsGetting started
The smallest useful thing you can do with it, and what each part means.
csharp
public class CreateBookEndpoint : Endpoint<CreateBookRequest, BookResponse>
{
public IBookRepository Repo { get; set; } = default!; // property injection
public override void Configure()
{
Post("/books");
Roles("admin");
Description(b => b.Produces<BookResponse>(201).ProducesProblem(400));
}
public override async Task HandleAsync(CreateBookRequest req, CancellationToken ct)
{
var book = await Repo.CreateAsync(req.Title, req.Year, ct);
await SendCreatedAtAsync<GetBookEndpoint>(
new { id = book.Id }, new BookResponse(book.Id, book.Title), cancellation: ct);
}
}
// Validation is discovered automatically.
public class CreateBookValidator : Validator<CreateBookRequest>
{
public CreateBookValidator() => RuleFor(x => x.Title).NotEmpty().MaximumLength(200);
}Advanced usage
Where the library earns its place over a simpler alternative.
csharp
public override void Configure()
{
Get("/books/{id}");
AllowAnonymous();
ResponseCache(60);
PreProcessor<TenantResolver>(); // runs before validation
PostProcessor<AuditLogger>();
Options(x => x.WithTags("Books"));
}
// Integration testing is first class.
public class CreateBookTests : TestBase<AppFixture>
{
[Fact]
public async Task Creates_a_book()
{
var (response, result) = await App.Client
.POSTAsync<CreateBookEndpoint, CreateBookRequest, BookResponse>(
new() { Title = "Dune", Year = 1965 });
response.StatusCode.Should().Be(HttpStatusCode.Created);
result.Title.Should().Be("Dune");
}
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- The endpoint returns 404 unexpectedly
- AddFastEndpoints or UseFastEndpoints is missing, or the endpoint class is not public.
- Injected properties are null
- Property injection requires a public settable property; a private field is not populated.
Best practices
- Keep one endpoint per file; the pattern loses its value if you group them.
- Put validation in a Validator<TRequest> so handlers never check input.
- Use the typed test client so route changes surface as compile errors.
- Prefer controllers when the team is large and already fluent in MVC conventions.
Background
Why it exists, and what it was reacting to.
FastEndpoints reacts to the controller pattern's tendency to accumulate unrelated actions in one class. Each endpoint is its own type, which keeps files small and dependencies precise.
