How To Structure Minimal APIs
Tags: aspnet, aspnetcore, dotnet, csharp
Published: 2023-09-16 10:51:08

---
title: How To Structure Minimal APIs
published: true
date: 2022-12-10 00:00:00 UTC
tags: aspnet,aspnetcore,dotnet,csharp
canonical_url: https://www.milanjovanovic.tech/blog/how-to-structure-minimal-apis
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y3vfspdjbqdeo9vm14cv.png
---
In this week's newsletter we are going to explore **Minimal APIs** , which were introduced in **.NET 6**.

**Minimal APIs** were introduced to remove some of the ceremony of creating traditional APIs with controllers. To define an endpoint, you can use the new extension methods, such as `MapGet` to define a **GET** endpoint.

I see one big issue with **Minimal APIs** , and that is the lack of clear guidance around how to structure applications built with **Minimal APIs**.

In this newsletter, I want to offer a few solutions for that problem.

Let's dive in.

## How To Create Minimal APIs?

Let's define a simple **Minimal API** application with two endpoints. We're going to create one `GET` endpoint for getting a list of products. And one `POST` endpoint for saving a product to the database.

We're using the powerful **DI** feature that allows us to inject services as expression arguments, which you can see in the two expressions below where we are injecting the `AppDbContext`.

```csharp
var builder = WebApplication.CreateBuilder(args);

// Configure EF and other services...

var app = builder.Build();

app.MapGet("/products", async (AppDbContext dbContext) =>
{
    return Results.Ok(await dbContext.Products.ToListAsync());
});

app.MapPost("/products", async (Product product, AppDbContext dbContext) =>
{
    dbContext.Products.Add(product);

    await dbContext.SaveChangesAsync();

    return Results.Ok(product);
});

app.Run();
```

And with this we have a functioning **Minimal API** that we can develop further as we continue to add more endpoints.

## The Problem With Maintaining Minimal APIs

There is one potential problem with structuring our **Minimal APIs** like in the previous example. If we keep adding the **Minimal API** endpoints in the same file, our API will become hard to maintain as it grows in complexity. How can we solve the maintance problem with **Minimal APIs**?

One solution can be to use extension methods to encapsulate the definiton of the **Minimal API** endpoints.

Here's an example of that:

```csharp
public static class ProductsModule
{
    public static void RegisterProductsEndpoints(this IEndpointRouteBuilder endpoints)
    {
        endpoints.MapGet("/products", async (AppDbContext dbContext) =>
        {
            return Results.Ok(await dbContext.Products.ToListAsync());
        });

        endpoints.MapPost("/products", async (Product product, AppDbContext dbContext) =>
        {
            dbContext.Products.Add(product);

            await dbContext.SaveChangesAsync();

            return Results.Ok(product);
        });
    }
}
```

And then inside of `Program` we need to register the endpoints:

```csharp
app.RegisterProductsEndpoints();
```

You can see that this simplifies our **Minimal API** definition, and we also have our endpoints grouped by feature in one place. I think this improve the maintainability of **Minimal APIs** , but it comes at a cost. And that cost is having to define extension methods for each group of endpoints you want to encapsulate, and then you have to remember to call that extensions method in `Program`.

Can we do better?

## Structuring Minimal API Projects With Modules

I want to introduce you to an interesting open source library called [Carter](https://github.com/CarterCommunity/Carter), which has a concept of modules that we can use to group endpoints.

Here's how we can define our `ProductsModule` with **Carter** :

```csharp
public class ProductsModule : ICarterModule
{
    public void AddRoutes(IEndpointRouteBuilder app)
    {
        app.MapGet("/products", async (AppDbContext dbContext) =>
        {
            return Results.Ok(await dbContext.Products.ToListAsync());
        });

        app.MapPost("/products", async (Product product, AppDbContext dbContext) =>
        {
            dbContext.Products.Add(product);

            await dbContext.SaveChangesAsync();

            return Results.Ok(product);
        });
    }
}
```

This takes care of configuring our **Minimal API** endpoints, but we still need to tell the framework to use these endpoints. We have to slightly modify the `Program` to register the required **Carter** services by calling `AddCarter`, and also map our endpoints by calling `MapCarter`.

```csharp
var builder = WebApplication.CreateBuilder(args);

// Configure EF and other services...

builder.Services.AddCarter();

var app = builder.Build();

app.MapCarter();

app.Run();
```

When we want to define additional **Minimal API** endpoints we just need to implement a new `ICarterModule`, and register our endpoints. **Carter** will automatically take care of registering the new endpoints after that.

## Would I Use Minimal APIs In a Real Project?

I think **Minimal APIs** have evolved nicely since they were first introduced in **.NET 6**. I would be careful with using them in very large applications, but I'm definitely going to explore options for using them on smaller projects.

A good use case can be for building a microservice that has a limited number of endpoints.

* * *

**P.S. Whenever you're ready, there are 2 ways I can help you:**

1. [**Pragmatic Clean Architecture:**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting) This comprehensive course will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture. [**Join 950+ students here.**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting)

2. [**Patreon Community:**](https://www.patreon.com/milanjovanovic) Think like a senior software engineer with **access to the source code** I use in my YouTube videos and **exclusive discounts** for my courses. [**Join 820+ engineers here.**](https://www.patreon.com/milanjovanovic)