In the evolution of ASP.NET Core, we have moved from the rigid structure of MVC (Model-View-Controller) to the streamlined simplicity of Minimal APIs. However, as applications grow, Minimal APIs can become disorganized, and Controllers often suffer from “bloat”—violating the Single Responsibility Principle.
Enter FastEndpoints.
This library is not just another framework; it is a philosophy shift. It wraps the performance of Minimal APIs in a structured, maintainable pattern known as REPR (Request-Endpoint-Response). In this post, we will dive deep into what FastEndpoints is, why it matters, and how to implement it in your .NET projects.
The Problem with Controllers
Traditionally, .NET developers group logic by resource. A UserController, for example, might handle Get, Create, Update, and Delete operations.
While this looks organized initially, it leads to several issues:
Constructor Bloat: A controller injecting dependencies for all its methods means every request instantiates services it might not need.
Hidden Coupling: Shared private methods inside a controller create tight coupling between unrelated endpoints (e.g., “Get User” logic bleeding into “Update User”).
Violation of SRP: A controller handles many responsibilities, rather than just one.
The Solution: The REPR Pattern
FastEndpoints implements the REPR pattern, which stands for Request-Endpoint-Response.
Instead of grouping by resource (a Controller), you group by feature (an Endpoint). Each endpoint is a distinct class dedicated to a single purpose (e.g., CreateUserEndpoint, GetUserEndpoint).
The Components
Request: A DTO (Data Transfer Object) defining what the client sends.
Endpoint: A class containing the logic for only that specific request.
Response: A DTO defining what the server returns.
Getting Started with FastEndpoints
Let’s look at how to implement a simple “Create User” feature using FastEndpoints in .NET 8.
Installation
First, install the necessary package via the NuGet Package Manager or CLI:
dotnet add package FastEndpoints
Configuration
In your Program.cs, register and enable FastEndpoints. It sits on top of the existing ASP.NET Core pipeline, so it integrates seamlessly.
using FastEndpoints;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFastEndpoints(); // Register services
var app = builder.Build();
app.UseFastEndpoints(); // Register middleware
app.Run();
Defining the Endpoint
Here is where the magic happens. Instead of a method inside a controller, we define a class.
The DTOs:
public class CreateUserRequest
{
public string FirstName { get; set; } = default!;
public string LastName { get; set; } = default!;
public string Email { get; set; } = default!;
}
public class CreateUserResponse
{
public string FullName { get; set; } = default!;
public string Message { get; set; } = default!;
}
The Endpoint:
using FastEndpoints;
public class CreateUserEndpoint : Endpoint<CreateUserRequest, CreateUserResponse>
{
public override void Configure()
{
Post("/api/users/create");
AllowAnonymous();
}
public override async Task HandleAsync(CreateUserRequest req, CancellationToken ct)
{
// Simulate database logic
var fullName = $"{req.FirstName} {req.LastName}";
// Send the response
await SendAsync(new CreateUserResponse
{
FullName = fullName,
Message = "User created successfully!"
}, cancellation: ct);
}
}
Breakdown of the Code
Inheritance: The class inherits from Endpoint<TRequest, TResponse>, providing strict typing immediately.
Configure(): This replaces route attributes ([HttpPost], [Route]). You define the configuration imperatively, which is often cleaner and more discoverable.
HandleAsync(): This contains your business logic. It takes the strongly-typed Request object and a CancellationToken automatically.
Key Features & Benefits
1. Built-in Validation
FastEndpoints integrates heavily with FluentValidation. You don’t need to manually check ModelState.IsValid. You simply define a validator, and the library handles the 400 Bad Request response automatically if validation fails.
public class CreateUserValidator : Validator<CreateUserRequest>
{
public CreateUserValidator()
{
RuleFor(x => x.Email).NotEmpty().EmailAddress();
RuleFor(x => x.FirstName).NotEmpty().MinimumLength(3);
}
}
2. Vertical Slice Architecture
By forcing you to create a file per endpoint, FastEndpoints naturally pushes your project toward Vertical Slice Architecture. All files related to a feature (the Endpoint, the Request/Response DTOs, the Validator, and the Mapper) can live in a single folder. This makes navigating code significantly easier than jumping between Controllers/, Models/, and Services/ folders.
3. Performance
Because FastEndpoints is a wrapper around ASP.NET Core’s Minimal APIs, it is extremely performant—significantly faster than traditional MVC Controllers and effectively on par with raw Minimal APIs. It builds the expression trees for mapping and validation at startup, ensuring runtime speed is maximized.
Conclusion
FastEndpoints offers the “sweet spot” for modern .NET API development. It provides the structure that Minimal APIs lack and removes the bloat that Controllers impose. If you are looking to build maintainable, high-performance, and type-safe APIs, adopting the REPR pattern with FastEndpoints is a powerful choice.
Happy Coding !!!