codete a quick introduction to minimal apis in net6 main ba534babb3
Codete Blog

A Quick Introduction to Minimal APIs in .NET 6

avatar male f667854eaa

16/02/2022 |

7 min read

Bartłomiej Lindert

With the release of .NET 6, Microsoft introduces a bunch of new features and improvements. Among them are Minimal APIs – an alternative way of developing REST APIs with minimal overhead and less boilerplate. While it isn’t a particularly new idea, because in the past there were open-source projects – like Nancy – which could achieve similar effects, it is nice to see this being now a part of the core .NET functionalities. 

The question is: for whom is this solution directed to? Basically, at the first glance, this solution might be great for newcomers, people who want to prototype or create a microservice with a minimal amount of files and dependencies.

In this article, we will go through the basics and, in the end, I’ll share some of my thoughts on the topic. So let’s jump right into this. :)

Table of contents:

  1. How to start with Minimal APIs
  2. Minimal APIs – pros and cons
  3. Final thoughts on Minimal APIs


How to start with Minimal APIs

First things first, we need to make sure that we’ve got .NET in version 6 on our machine (it can be checked using cli: dotnet –version).

If that’s the case, we can start a new project by simply using the following Dotnet CLI command: 

dotnet new web

After that new project will be created structure: 

minimal AP Is 1 b01fcd7836

What interests us is the Progam.cs file, so let’s check what’s inside.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");


In just 4 lines of code, we’ve got a working example and a backbone of the REST API. No unnecessary usings, no controllers, just one file – it’s really easy to go straight to the point. This is something that may look really familiar to the developers who previously worked with Node.js. One may say that this is the true essence of the lightweight framework.

So we’ve got our “Hello world” example, which – as for now – is basically doing nothing. Let’s expand it a little bit with some additional routes, documentation, and basic business logic. For this, we’ll create a basic CRUD for managing articles. 


Adding additional routes

So the first question that pops up in mind is: “How do I add POST, DELETE, PUT request?”. This is really simple and looks like this:

app.MapGet("/article", () => "Get all articles");
app.MapPost("/article", () => "Post new article");
app.MapPut("/article", () => "Edit an article");
app.MapDelete("/article", () => "Delete an article");

As you can see each and every HTTP method has its own function which takes two parameters: 

  • pattern to specify the route,
  • delegate function which will handle the request.


Adding Swagger 

Documenting our API is a good practice, so let’s see how to do it with Minimal APIs. 

For starters, we need to get Swagger NuGet package, so we’ll download it using Dotnet CLI:

dotnet add package swashbuckle.aspnetcore

Then, we need to modify the Program.cs to register the newly added package to our project in the dependency injection. 

var builder = WebApplication.CreateBuilder(args);



var app = builder.Build();


app.UseSwaggerUI(c =>


    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Minimal APIs Example");

    c.RoutePrefix = "";


Now, after we run dotnet run in the CLI and jump into the browser, the documentation should be working as intended.

minimal AP Is 2 404555e84e

Adding DI to the mix

Alright, we’ve got our routes specified and documented, so let’s add some business logic. 

For this reason, we will create:

  • Article as a record, which will serve as our model,
  • ArticleRepository which will be our in-memory repository for mocking data access.

public record Article(int id, string title, string author);

public class ArticleRepository
    private readonly List<Article> _articles = new List<Article>();

    public Article? GetById(int id) => _articles.FirstOrDefault(article => == id);
    public IList<Article> GetAll() => _articles;
    public void Add(Article article) => _articles.Add(article);
    public void Edit(Article article)
        int index = _articles.FindIndex(item => ==;
        _articles[index] = article;
    public void Remove(int id)
        int index = _articles.FindIndex(article => == id);

Now, what’s left is to register our ArticleRepository in DI Container:


Awesome! Now, we’ll modify our routes by injecting the repositories into them and modifying the response. (I will explain how to do this in detail on a POST request.)

app.MapPost("/article", (ArticleRepository repository, Article article) =>
    return Results.Created($"/article/{}", article);

Let’s break this down.

First, look into the parameters inside the delegate function:

  • repository – is injected from DI,
  • article – is taken from request’s body.

It’s worth noting that we can be explicit by using attributes so it would look like this:

[FromServices] ArticleRepository repository, [FromBody] Article article

Next, let’s look into the function’s body. Here, we use our repository to add an article to the collection and return a response with code 201, which means that the resource was created successfully.

Last but not least, after the mapPost function, using the fluent API, we’ve got the Produces<Article>(201) function, which enriches Swagger with information about the response. 

Now, we can jump into Swagger again, to check if everything is working as intended. If it does, it should look like in the example below:

minimal AP Is 3 0796de490d

This concludes the example part, but – to be honest – we’ve just scratched the surface of the topic. There are a lot of things that can be improved, like adding validation, or using MediatR instead of injecting the repository right into routes. But, I think that in the current form, it’s a great way to start things up. If you want to check the example and tinker around it yourself, you can find the solution here.

Also, if you want to read more about Minimal APIs (in a really easy-to-digest form) I would highly recommend this David Fowler’s Github Gist

Read: 9 REST API Best Practices to Follow

Minimal APIs – pros and cons

So now, after we’ve seen how they work in action, let’s answer the question about the advantages and disadvantages of the Minimal APIs.

Advantages of Minimal API in .NET 6

  • Easy to start, even for newcomers.
  • Less boilerplate means we can go straight to the point.
  • Great for prototyping and microservices.
  • More choices on how we want to build our APIs.
  • Better performance than the MVC because of less overhead.

Disadvantages of Minimal API in .NET 6

  • Compared to MVC, it may be harder to maintain as the project grows.
  • Project structure is not as obvious as in the MVC.
  • Some features from the standard MVC are missing.

Read: 5 Things You Need to Know About the API-First Approach

Final thoughts on Minimal APIs in .NET 6

So should we be excited about the Minimal APIs? From my own viewpoint, yes – we should. It’s a step in the right direction, as it’s trying to reach a place dominated by Node.js. Also, it’s a good place to start for a newbie with minimal .NET knowledge, someone who wants to create a quick proof of concept example, or for someone just starting a new microservice project. 

Well, of course, there are disadvantages to this solution. One of the biggest concerns is the fact that everything can be in one place and it may lead up to a “big ball of mud”. However, it’s not like we are forced to put the entire code of the application into Progam.cs. We can simply move routes definition to other files, creating modules to slim out our main file. Projects like Carter may help with setting this out. 

But should we just abandon the old way? Should we just abandon the MVC? The answer is no, but the ability to choose the right tool that is more suitable for the problem we’re facing is certainly not a bad thing. Overall, I’m looking forward to seeing how Minimal APIs shape the future of building REST APIs using the .NET platform.

Rated: 5.0 / 2 opinions
avatar male f667854eaa

Bartłomiej Lindert

Software Developer specialized in .NET, who loves finding new ways of improving his code and expanding his knowledge. After work, Japanese culture and cycling fan.

Our mission is to accelerate your growth through technology

Contact us

Codete Global
Spółka z ograniczoną odpowiedzialnością

Na Zjeździe 11
30-527 Kraków

NIP (VAT-ID): PL6762460401
REGON: 122745429
KRS: 0000983688

Get in Touch
  • icon facebook
  • icon linkedin
  • icon instagram
  • icon youtube
  • Kraków

    Na Zjeździe 11
    30-527 Kraków

  • Lublin

    Wojciechowska 7E
    20-704 Lublin

  • Berlin

    Bouchéstraße 12
    12435 Berlin