Building a Web API in .NET using Minimal APIs

KhalilKhalil
3 min read

With the introduction of .NET 6, Microsoft brought a simplified approach to creating web applications and APIs called Minimal APIs. This new model reduces boilerplate code and provides a streamlined way to define and handle HTTP requests. In this article, we’ll walk through the steps to create a basic Web API using Minimal APIs in .NET.

Prerequisites

Before you start, ensure you have the following installed:

  • .NET 6 SDK or later (I'm using .NET 8)

  • Your favourite IDE (I'm using JetBrains Rider)

You can check also this article on how to use Fast Endpoint instead of the custom implementation here.

Step 1: Create a New .NET Project

Since I'm using Rider, the window for creating a new project should resemble the screenshot below. I have chosen "BookStore" as the Solution name and "BookStore.HttpApi" for our Web API, with the SDK set to version 8.0.

Rider should generate the default template for you as you can see below:

Without making any changes to the default template, click the run button in the toolbar to view your app in the browser.

Step 2: Organising Minimal API endpoints

The objective of this step is to create a few minimal endpoints for our BookStore, such as GetById, GetAll, and CreateBook.

Before creating our endpoints, let's create an interface and some extension methods to help us automatically register our endpoints, which will be injected automatically as part of the pipeline.

In bookStore.HttpApi project, let's create a folder named Utilities and then add the IEndpoint interface and EndpointExtensions static class

namespace BookStore.HttpApi.Utilities;

public interface IEndpoint
{
    void MapEndpoint(IEndpointRouteBuilder app);
}
using System.Reflection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace BookStore.HttpApi.Utilities;

public static class EndpointExtensions
{
    public static IServiceCollection AddAppEndpoints(this IServiceCollection services, Assembly assembly)
    {
        var descriptors = assembly
            .DefinedTypes
            .Where(type => type is { IsAbstract: false, IsInterface: false } &&
                           type.IsAssignableTo(typeof(IEndpoint)))
            .Select(type => ServiceDescriptor.Transient(typeof(IEndpoint), type))
            .ToArray();

        services.TryAddEnumerable(descriptors);

        return services;
    }

    public static IApplicationBuilder MapEndpoints(this WebApplication app)
    {
        IEnumerable<IEndpoint> endpoints = app
            .Services
            .GetRequiredService<IEnumerable<IEndpoint>>();

        foreach (var endpoint in endpoints)
        {
            endpoint.MapEndpoint(app);
        }

        return app;
    }
}
using System.Reflection;
using BookStore.HttpApi.Utilities;
var builder = WebApplication.CreateBuilder(args);

//Add this line and remove the default template: WeatherForecast
builder.Services.AddAppEndpoints(Assembly.GetExecutingAssembly());

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.MapEndpoints();

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

app.UseHttpsRedirection();
app.Run();

In the same project, let's create a folder named "Endpoints" to organise our endpoints. Inside the "Endpoints" directory, add another directory named "Books" where we will define our GetById, CreateBook, GetAll endpoint classes.

using BookStore.HttpApi.Utilities;

namespace BookStore.HttpApi.Endpoints.Books;

public class CreateBook: IEndpoint
{
    public void MapEndpoint(IEndpointRouteBuilder app)
    {
        app.MapPost("/books/create", () =>
        {
            return Results.Ok("Create works!!");
        }).WithTags("Books");
    }
}
using BookStore.HttpApi.Utilities;

namespace BookStore.HttpApi.Endpoints.Books;

public class GetAll : IEndpoint
{
    public void MapEndpoint(IEndpointRouteBuilder app)
    {
        app.MapGet("/books/all", () =>
        {
            return Results.Ok("Get All works!");
        }).WithTags("Books");
    }
}
using BookStore.HttpApi.Utilities;

namespace BookStore.HttpApi.Endpoints.Books;

public class GetBookById : IEndpoint
{
    public void MapEndpoint(IEndpointRouteBuilder app)
    {
        app.MapGet("/books/{id}", () =>
        {
            return Results.Ok("Get books by id works!!");
        }).WithTags("Books");
    }
}

This should be straightforward, the endpoints implements IEndpoint interface we created earlier. That's what you get when you run the app in the browser:

Conclusion

Minimal APIs in .NET offer a streamlined and efficient way to build lightweight web APIs. By reducing the amount of boilerplate code required, they allow developers to focus on the core functionality of their applications. This guide covered the basics of setting up and running a Minimal API, and with these fundamentals, you can start building more complex and robust web services. Happy coding!

0
Subscribe to my newsletter

Read articles from Khalil directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Khalil
Khalil