How Asp.Net Core minimal API template is useful to kick start a project with code

Introduction

These daysMinimal APIs have become one of the most talked-about features, not only because it provide a streamlined, lightweight way to build HTTP APIs with .NET but also reduce the boilerplate code required to create web services. In this tutorial, I will dive deep into how to set up Minimal APIs, build a simple API, and handle requests efficiently with .NET 8.

Why Minimal APIs?

Before diving into the code, let’s quickly discuss why Minimal APIs are the future of web development with .NET:

  1. Less Boilerplate: Reduced complexity compared to traditional MVC/Web API patterns.
  2. Faster Development: Great for microservices and small applications where speed is critical.
  3. Clean and Simple: Code remains clear and concise, improving maintainability.

Setting Up Your .NET 8 Project

To get started, make sure you have the latest version of .NET 8 installed. If you haven't done so already, you can download it from the official Microsoft .NET site.

Once you have .NET 8 installed, create a new Minimal API project:

dotnet new web -n YourProjectName

This is a way to create through the .NET CLI where web is the name of the project template, which by default is a minimal API, and -n is to specify the name of the project.

Alternatively, we can open Visual Studio, click on Create New Project, and in the templates search bar search for minimal, and we can see the project.

Let's select ASP.NET Core Web API and in the next screen provide solution and project names, and click next, where we will see the following options, and I have highlighted the checkbox which will make that a minimal API.


Create our first Endpoint

Now, let's create a simple API to manage a list of users. First open Program.cs we should see that there’s a default get endpoint configured.

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");

  Let's remove this boilerplate code and add a /users endpoint.

// GET /users - returns all users
app.MapGet("/users", () =>
{
    // Dummy user model
    record User(int Id, string Name, string Email);

    // In-memory list of users (defined inside the endpoint)
    var users = new List
    {
        new(1, "Alice", "alpha@example.com"),
        new(2, "Bob", "beta@example.com"),
        new(3, "Charlie", "gema@example.com")
    };
    return Results.Ok(users);
});

MapGet("/users", ...)This creates a GET endpoint for /users,the result is returned as an anonymous object containing user data. When you run this app, you can navigate to https://localhost:{port}/users and see the list of users as a JSON response.

Adding More Routes

By following the RestFull specification, let’s add POST, PUT, DELETE, GET by id, and PATCH routes to enhance the API. First, let’s add a POST route for adding new users.

// POST /users - Create a new user
app.MapPost("/users", (User model) =>
{
    if (users.Any(u => u.Id == model.Id))
    {
        return Results.Conflict("User with the same ID already exists.");
    }
    users.Add(model);
    return Results.Created($"/users/{model.Id}", newUser);
});

In the above snippet, users is an instance of a List<User>, and this endpoint returns a 201 HTTP status code in response. Next, let's try to add the remaining endpoints.


// PUT /users/{id} - Update an existing user
app.MapPut("/users/{id:int}", (int id, User updatedUser) =>
{
    var user = users.FirstOrDefault(u => u.Id == id);
    if (user is null) return Results.NotFound();

    users.Remove(user);
    users.Add(updatedUser);

    return Results.Ok(updatedUser);
});

// DELETE /users/{id} - Delete a user
app.MapDelete("/users/{id:int}", (int id) =>
{
    var user = users.FirstOrDefault(u => u.Id == id);
    if (user is null) return Results.NotFound();

    users.Remove(user);
    return Results.NoContent();
});
// PATCH /users/{id} - Partially update a user
app.MapPatch("/users/{id:int}", (int id, UserPatchModel patch) =>
{
    var user = users.FirstOrDefault(u => u.Id == id);
    if (user is null) return Results.NotFound();

    var updatedUser = user with
    {
        Name = patch.Name ?? user.Name,
        Email = patch.Email ?? user.Email
    };

    users.Remove(user);
    users.Add(updatedUser);
    return Results.Ok(updatedUser);
});

Conclusion:

Minimal APIs in .NET simplify building lightweight, efficient APIs with fewer lines of code. In this quick tutorial, I have shown how easy it is to create routes, handle HTTP requests, and build simple endpoints with minimal configuration. Whether building microservices, APIs for small applications, or experimenting with new features in .NET 8, Minimal APIs offer a great foundation to kickstart your next project.


Next Steps:

This was all the basic introduction of a minimal API project and idea, and I am almost thinking of extending this post to a series, and inthe  next posts, I would like to cover:

  1. Adding database support with Entity Framework Core.
  2. Implementing authentication and authorization.
  3. Exploring middleware and other advanced features of Minimal APIs.