What are Minimal APIs in ASP.NET Core 6
Tags: aspnetcore, bogus, csharp, dotnet
Published: 2022-08-29 06:49:08

---
title: What are Minimal APIs in ASP.NET Core 6
published: true
tags: aspnetcore,Bogus,csharp,dotnet
canonical_url: https://coderethinked.com/what-are-minimal-apis-in-asp-net-core-6/
date: 2022-08-30 5:30 UTC
---

## What is a Minimal API?

The goal of Minimal APIs in ASP.NET Core is to create HTTP API’s with minimum dependencies.

In the world of microservices, the backend API’s are becoming way too smaller and easier to work with. The minimal API’s may come in handy when working with small API’s which has only a few dependencies.

## How to create Minimal API’s?

We can create minimal API’s either with Visual Studio 2022 or dotnet CLI.

### With dotnet CLI

```cli
dotnet new webapi -minimal -o TodoApi
cd TodoApi
code -r ../TodoApi
```

### With Visual Studio 2022

I’m not writing a step-by-step guide on how to create minimal APIs on visual studio 2022 as [Microsoft documentation has those steps already](https://docs.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-6.0&tabs=visual-studio).

But, an important step when creating ASP.NET Core Web API is to **select** `.NET 6 framework` and **uncheck** the `"Use controller (uncheck to use minimal APIs)"` option in the Additional information dialog.

![Setup wizard for minimal API's in Visual Studio 2022](https://coderethinked.com/wp-content/uploads/2022/07/image.png)
_Figure 1: setup minimal API’s in Visual Studio 2022_

Notice we also have an option not to use the top-level statements checkbox here. If we check the `"Do not use top-level statements"` checkbox, we will have the usual `Program.cs` file with `Main` method in it instead of top-level statements.

Once we create a minimal API, we will have the default weather app which generates 5 random weather numbers for us.

Here is what the `Program.cs` file looks like with minimal API.

```c#
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateTime.Now.AddDays(index),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast");

app.Run();

internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

```

Within the `Program.cs` file, we see swagger is added to services, and swagger UI is also added to the request pipeline.

We can run and see if we want.

## Where are `ConfigureServices()` and `Configure()` methods?

If you are not aware of these methods. The `ConfigureServices()` and `Configure()` methods are called by the ASP.NET Core runtime when the app starts. But, with minimal API’s these methods are removed and we can write our dependencies/middleware directly in the `Program.cs`.

If you want to register any services to the container then you’ve to add them after the builder is created with `CreateBuilder(args)` method but should not be after the `builder.Build()`. Assume that **this is our old ConfigureServices method**.

And if you want to add anything to the request pipeline like our old Configure method, you’ve to configure them with after `builder.Build()` but before `app.Run()`. Assume that **this is our old Configure method**.

![Depicting the ConfigureServices and Configure methods in Program.cs in Minimal API's](https://coderethinked.com/wp-content/uploads/2022/07/image-2-1024x433.png)
_Figure 2: Depicting the ConfigureServices and Configure methods in Program.cs_

## Ok, where is the main entry point?

The `Program.cs` file now does not have any `Main` method. This is because of the new language feature introduced as part of [C# 9: Top-Level statements](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) (we could configure the minimal APIs to generate the Main method by checking the `Do not use top-level statements` checkbox mentioned in Figure 1).

Behind the scenes, the compiler will inject the code you wrote in `Program.cs` into the main method for us.

Here is the Intermediate Language (IL) generated for Program.cs file in ILDASM

![Intermediate Language (IL) showing Main method in Minimal API](https://coderethinked.com/wp-content/uploads/2022/07/image-1-1024x399.png)
_Intermediate Language showing the Main method in Minimal API_

## Setting up Repository for minimal API

Before we write minimal API’s let’s build a User repository.

```c#
public interface IUserRepository
{
    User GetUser(int id);
    bool UpdateUser(int id, User user);
    void DeleteUser(int id);
}

public class UserRepository : IUserRepository
{
    private List<User> _users = new List<User>();

    public UserRepository()
    {
        GenerateSeedData();
    }

    public User GetUser(int id)
    {
        return _users.FirstOrDefault(u => u.Id == id);
    }

    public bool UpdateUser(int id, User user)
    {
        var dbUser = _users.FirstOrDefault(u => u.Id == id);
        if (dbUser is null) return false;

        dbUser.UserName = user.UserName;
        dbUser.FirstName = user.FirstName;
        dbUser.LastName = user.LastName;

        return true;
    }

    public void DeleteUser(int id)
    {
        var user = _users.FirstOrDefault(u => u.Id == id);
        if (user is null) return;

        _users.Remove(user);
    }

    private void GenerateSeedData()
    {
        _users = new Faker<User>()
            .StrictMode(true)
            .RuleFor(u => u.Id, f => f.IndexFaker)
            .RuleFor(u => u.UserName, f => f.Person.UserName)
            .RuleFor(u => u.FirstName, f => f.Person.FirstName)
            .RuleFor(u => u.LastName, f => f.Person.LastName)
            .Generate(50);
    }
}
```

Our user repository has 3 basic operations

1. We can get a user by their Id
2. Update the user’s first name, last name, and also user name
3. Delete a user by Id

With the Faker class, we generated seed data for our repository. Faker class is part of Bogus library and Bogus is a fake data generator for C#. If you need more information about Bogus and how to generate fake data, [take a look at this article](https://dev.to/karthikchintala/how-to-generate-fake-data-in-c-2f4p-temp-slug-9485001).

## Writing a minimal API

Now, let’s write our minimal API’s for user operations. Ideally, we’d have managers to have some business logic and also call the repositories. But, for this article let’s wire the repository directly to the APIs.

```c#
app.MapGet("/user/{id}", (int id, IUserRepository userRepository) =>
{
    var user = userRepository.GetUser(id);
    if (user is null) return Results.BadRequest();

    return Results.Ok(user);
}).WithName("GetUsers");

app.MapPut("/user/update/{id}", (int id, User user, IUserRepository userRepository) =>
{
    return userRepository.UpdateUser(id, user);
}).WithName("UpdateUsers");

app.MapDelete("/user/{id}", (int id, IUserRepository userRepository) =>
{
    userRepository.DeleteUser(id);
    return Results.Ok();
}).WithName("DeleteUser");
```

We have different extension methods for GET (MapGet), POST (MapPost), PUT (MapPut), DELETE (MapDelete) HTTP verbs. All these extension methods take the URL as the first argument and a Delegate as a second parameter. These methods are like our action methods in the MVC world.

Notice we are adding the `IUserRepository` to every endpoint here. The `IUserRepository` will be resolved with dependency injection as one would expect.

We also see `Results.Ok()`, `Results.BadRequest()` methods in our API’s. `Results` is a static helper class that exits in `Microsoft.AspNetCore.Http` namespace which provides basic return types for API’s. [Here is the list of built-in results in the Results class](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0#built-in-results).

At the end of the API, we have `.WithName` method which is optional here. The argument you provide here will be `operationId` in the `swagger.json` file for each of the operations.

Now, Let’s run and see how they all work.

![Demo of minimal apis on coderethinked.com](https://coderethinked.com/wp-content/uploads/2022/07/minimalapisdemo.gif)
_Demo: Minimal API demo_

## Full Program.cs code

Here’s the `Program.cs` file after adding our user endpoints.

```c#
using MinimalAPIs.Repositories;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddSingleton<IUserRepository, UserRepository>();

var app = builder.Build();
app.MapControllers();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapGet("/user/{id}", (int id, IUserRepository userRepository) =>
{
    var user = userRepository.GetUser(id);
    if (user is null) return Results.BadRequest();

    return Results.Ok(user);
}).WithName("GetUsers");

app.MapPut("/user/update/{id}", (int id, User user, IUserRepository userRepository) =>
{
    return userRepository.UpdateUser(id, user);
}).WithName("UpdateUsers");

app.MapDelete("/user/{id}", (int id, IUserRepository userRepository) =>
{
    userRepository.DeleteUser(id);
    return Results.Ok();
}).WithName("DeleteUser");

app.Run();
```

## Limitations of Minimal API’s

Minimal APIs also has few limitations.

- **No support for filters**. Yes, we cannot use exception filters, result filters, action filters etc
- **No built-in support for validation** (IModelValidator). If you’ve been using `ModelState.IsValid` on your controller actions then it won’t work with Minimal API’s. You have to write your own validators to validate the input. 
- **No support for OData, JsonPatch, ApiVersioning**

## When to use Minimal API’s?

As you can see in this post, we’ve come far from the MVC mindset here. We don’t see any controllers or action methods that typically create our endpoints in the Web API’s.

If you are starting with a brand new microservice that is fairly small, then it’s better to start with minimal API.

But, if you think your backend is going to have more endpoints in the future like an enterprise backend then using controllers might be a better choice.

## References

- [Minimal API](https://docs.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-6.0&tabs=visual-studio)
- [What is Bogus](https://dev.to/karthikchintala/how-to-generate-fake-data-in-c-2f4p-temp-slug-9485001)
- [Built-in Results types for Minimal APIs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0#built-in-results)
- [Top Level Statements](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements)

The post [What are Minimal APIs in ASP.NET Core 6](https://coderethinked.com/what-are-minimal-apis-in-asp-net-core-6/) appeared first on [Code Rethinked](https://coderethinked.com).