8 minutes read

Should you use WebApi or Minimal APIs?

For those expecting a juicy article with me either valiantly defending Minimal APIs or burning them to the ground, I’ll have to disappoint you. I want to start off by saying that both Minimal APIs and WebAPI are valid choices. Both have their use cases and both should be considered a part of your vast set of tools to program cool stuff with .NET. Now let’s get into what Minimal APIs are and more importantly: why you should use them.

Minimal photo of a cup of coffee

A minimal rundown on building .NET APIs

Let’s get the history out of our way.

Back in the day, with the release of MVC 4, Microsoft also released ASP.NET Web API. Web API was a framework that simplified the creation of REST HTTP services. This was done by adapting familiar MVC concepts like Controllers, Filters, and Routes into something that could be used to create APIs. This was the main way of writing REST (style) APIs until we got .NET 6.

.NET 6 introduced a new way to write APIs: Minimal APIs. As the name already suggests, Minimal APIs are a “simplified” way to create APIs. The style is heavily inspired by frameworks like Express in Node, FastApi in Python, and Gin for Go, with a focus on going from nothing to a working API in as few lines of code as possible.


_10
var builder = WebApplication.CreateBuilder(args);
_10
var app = builder.Build();
_10
_10
app.MapGet("/hello", (User user) => user.ReadsWeekenddive
_10
? "Hello, you're awesome"
_10
: "Hello, go read https://www.weekenddive.com");
_10
_10
app.Run();

Many people take the name “Minimal API” the wrong way. They believe this style of writing APIs is only suitable for hobby projects, proof of concepts, or demos. However, since .NET 7, Minimal APIs have been on par with Controller-based APIs in ASP.NET Core. The old way of writing APIs required following opinionated boilerplate, while Minimal APIs offer more flexibility and can be tailored to fit the specific needs of a project. Additionally, most features of Minimal APIs are opt-in, while Web API is opt-out.

Why are we writing APIs with controllers?

Web API has a lot of rich features, like versioning, authentication, and authorization. You get all this and more out of the box with Web API. But it does come with quite a rigid convention and a lot of boilerplate. Web API (kinda) forces you to group logic simply because it is part of the same resource URL. This isn’t a problem with small CRUD APIs. But when you have a multitude of different actions, like the GitHub API, it stops making sense.

Controller-based APIs often require you to disregard the Single-Responsibility and Open-Closed principles in order to comply with MVC conventions, even though there is no Model or View involved. This can also have a negative impact on API performance, as services may be initialized through Dependency Injection that are not necessary for the requested action.

And when you circumvent these issues by splitting up the same resources over different controllers, ask yourself why you are using controllers in the first place.

When should you use Minimal APIs?

Minimal APIs are best suited for micro, small, middle, and large projects. You could also use it for demos, a proof-of-concept, microservices, or very large monolithic projects.

See what I did there? Minimal APIs can be used wherever you want. They should be seen as just another tool in your ever-growing toolkit. They aren’t better or worse than Web API.

Minimal APIs do have a big advantage over Web API: they are fully flexible. You, the developer, can choose how to use them. You decide what convention you want to adhere to, what and how much boilerplate you require, when resources or actions should be grouped together and when not. And you can decide all of that for each feature you write. Your product endpoints might benefit from grouping all CRUD operations in one file, while it makes more sense to use the REPR pattern for all your other endpoints. You decide, even when all endpoints reside in one single project.

With Minimal APIs, you get a lot of the same features you get with Web API, but you gain a lot of flexibility. Flexibility that allows your software to evolve to the ever-changing requirements any software development cycle is subject to.

Minimal does not mean it lacks features

When Minimal APIs were first released, we lacked important features. But with .NET 7 and the release of Filter support and Route Groups, Minimal APIs are almost as feature complete as Web API controllers.

Filters allow us to write generic business logic that:

  • runs before and after the endpoint is handled
  • inspects and optionally modifies arguments
  • intercepts or changes the response behavior of an endpoint

Route Groups enable us to group endpoint handlers under a single group with shared functionality. This eliminates the need to duplicate functionality across each CRUD handler for the /product resource. For example:


_13
app.MapGroup("/public/products")
_13
.MapGet("/", (ProductService service)=>service.GetAllProducts())
_13
.MapGet("/{id}",(ProductService service, int id)=>service.GetProduct(id))
_13
.WithTags("Public")
_13
_13
app.MapGroup("/admin/products")
_13
.MapPost("/",
_13
(ProductService service, Product product)=>service.CreateProduct(product))
_13
.MapPut("/{id}",
_13
(ProductService service, int id, Product product)=>service.UpdateProduct(id, product));
_13
.WithTags("Private")
_13
.AddEndpointFilterFactory(SomeFilterLogic)
_13
.RequireAuthorization();

Several small features are missing in Minimal APIs. Microsoft has listed these here. But besides these features, Minimal APIs support all the things we know and like from Web API controllers, such as:

  • Parameter binding (including support for custom binding by implementing either TryParse or BindAsync)
  • Filters
  • Middleware
  • Authentication and Authorization
  • OpenAPI support

And more…

Using Minimal APIs with the Startup Class

Minimal APIs weren’t the only new thing in .NET 6. We also got Top-Level functions. With Top-Level functions, we can ditch the whole Main method entry point. With this change, we also got a new way to initialize our ASP.NET Core applications. Instead of using a separate Startup class, we got the WebApplication.CreateBuilder(args) method that we can call in the Program.cs file. In short, with .NET 6 we now can simplify the way we bootstrap our application into:


_10
var builder = WebApplication.CreateBuilder(args);
_10
builder.Services.RegisterSomeServices();
_10
var app = builder.Build();
_10
app.MapGet("/",() => "Hello World");
_10
app.Run();

However, the project you’re currently working on was made years ago and uses the trusted Startup class. Luckily, you can still use Minimal APIs. With the new Top-Level functions, the builder.Services is the same as ConfigureServices in the Startup class. And everything below builder.Build() would replace the Configure method. And while app implements IEndpointRouteBuilder in the Top-Level functions, the app argument we often find in the Configure method does not. So, simply slapping on a MapGet in your Configure method won’t get you far. Instead, try the following:


_10
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
_10
{
_10
app.UseEndpoints(endpoints =>
_10
{
_10
endpoints.MapGet("/",() => "Hello World");
_10
});
_10
}

Note: UseEndpoints should be one of the last, if not the last middleware you apply in the Configure method.

TL;DR

Minimal APIs are not necessarily superior or inferior to Controller APIs. They offer a new approach to writing APIs with .NET that is lighter than Controllers, as they don't include a pipeline with features that may not be needed.

Minimal APIs offer more flexibility in how you structure your own code. When looking objectively at Controllers you might find that grouping all features by resource name doesn’t make a lot of sense. Minimal APIs shine in their ability to grow alongside your project and its requirements, enabling features, extending functionality, and grouping however you see fit.

Personally, I think I prefer Minimal APIs over Controllers unless I see a clear need for Controllers. Minimal APIs are easier to start with and I can write my own logic to wire up my endpoints when my requirements change.

What to read next:

I really hope you enjoyed this article. If you did, you might want to check out some of these articles I've written on similar topics.