Why I Build My APIs with FastEndpoints

I stopped writing controllers. Then I stopped writing Minimal APIs too.

Controllers were fine until they weren’t. One endpoint’s logic ended up spread across attributes on the action, the action method itself, and filter classes living somewhere else entirely. When something broke, I went hunting across three files to understand one request.

So I tried Minimal APIs. No controllers, no ceremony, it felt like the framework finally got out of my way. Then the project grew. My Program.cs quietly became a 400-line mess of routing, validation, and error handling all blurred together. The “minimal” API had become a maximal mess.

Both roads led to the same place: endpoints scattered where you’d least expect them.

What I use now

These days I build my endpoints with FastEndpoints. It’s a .NET library built on the REPR pattern, Request, Endpoint, Response. One class per endpoint. Here’s the whole shape:

Fastendpoints Endpoint Class Handling Get /Orders

And with a request body:

Fastendpoints Endpoint Class Handling Post /Orders

Route, verb, and handler, all in one findable class. And wiring it up takes two lines in Program.cs:

Registering Fastendpoints In Program.cs

That’s it. Program.cs goes back to being a menu.

Three things that sold me

1. One class per endpoint. Everything about an endpoint, its route, its verb, its auth, its logic, lives in one file with a predictable name. When a request misbehaves at 2am, I know exactly where to look. This is the same instinct I’ve applied on every legacy migration: draw the seams first, then fill in the details.

2. Validators are separate classes. FastEndpoints has FluentValidation-style validation built into the pipeline. You write a validator class for the request, and it runs before your handler ever sees the input:

Fastendpoints Validator Class For Createorderrequest

Invalid input never reaches your handler code. It just doesn’t get that far. No more defensive null-checks at the top of every action.

3. Pre/post processors. Cross-cutting concerns, logging, auth checks, caching behaviour, get their own processor classes that run before or after the endpoint:

Fastendpoints Pre-Processor For Logging Requests

No middleware soup, no action filters scattered across the project. The pipeline for an endpoint reads top to bottom in one place.

Why it fits how I build: modular monoliths

This is the real reason I chose FastEndpoints, and it’s architectural, not cosmetic.

I build with modular monolith architecture. Each module is a bounded context, its own endpoints, its own validators, its own use cases, with hard boundaries between modules and no tangling across them. It’s the structure that lets a monolith stay maintainable as it grows: break the system down into modules, and each module breaks down into use cases.

FastEndpoints maps onto that shape almost perfectly. One class per endpoint means a module is just a folder of endpoints, each owning its request, its validation, and its handler. A use case like “create order” is a self-contained unit: the endpoint class, its validator, its processors, all living together inside the module boundary. Nothing leaks across.

With controllers, I’d have to impose that structure through discipline and code reviews. With Minimal APIs, I’d have to invent it from scratch. With FastEndpoints, the library’s natural shape and my architecture’s natural shape agree with each other. The right structure is the path of least resistance instead of something I have to fight for.

That’s what “better structure” actually means to me: not more folders, but boundaries the code can’t accidentally cross.

And it’s genuinely fast

This part matters to me: FastEndpoints is built for throughput, without the MVC overhead. It’s consistently among the fastest ways to serve HTTP in .NET. When you’ve spent years optimising page loads and API response times, you notice when a library doesn’t make you pay a tax for its abstractions.

The honest caveats

I’ll say what I’d tell my team: it’s a community library, not a Microsoft framework. That means a smaller ecosystem, fewer Stack Overflow answers, and your team has to learn the REPR pattern before they’re productive. Hiring-wise, “FastEndpoints experience” isn’t a checkbox candidates arrive with.

For me, the trade paid off in the first week. I could find every endpoint in the codebase by filename. Onboarding a new developer meant pointing at one folder and saying “every file here is one endpoint; they all look the same.” That consistency is worth more than framework familiarity.

The real lesson

The code doesn’t rot because the tech is wrong. It rots because nobody protected the structure.

Controllers, Minimal APIs, FastEndpoints, the tool matters less than the discipline. But I’ll take every advantage I can get, and a library that makes the right structure the default shape of the code is an advantage I’ll keep taking.

Same lesson as every migration I’ve done: structure is a choice. FastEndpoints just makes the right choice the easy one.

Controllers, Minimal APIs, or FastEndpoints, what are you building endpoints with?

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.

Hello 👋🤗 In case this is your first time reading

I know it been a long time since I posted

This might be kinda boring. When we all hear about

A not so short episode on my struggle on how

I think every time we all think of failure, it’s

A summary rant about how I am not depressed 😂,

This year has been really amazing. I know I probably

I shared 3 main lessons I learnt from working on