Building Your First Minimal API in .NET

Minimal API is a new feature introduced in ASP.NET Core 6.0 that simplifies the process of building HTTP APIs. It’s a lightweight, opinionated framework that allows developers to create APIs with less boilerplate code and configuration.

Why Minimal API?

Minimal API is a new feature in .NET 6 that allows the creation of simple services with less code and dependencies. It uses C# 10 features and is inspired by other technologies like node.js, python, and go. It can be created directly in the Program.cs.

Minimal APIs are great for prototyping and building microservices due to their simplicity and reduced overhead. They are lightweight and efficient, making them ideal for quickly building and testing new ideas or small-scale applications.

While Minimal APIs offer many advantages, they may not be suitable for more complex APIs with a large number of endpoints or more advanced functionality. This is because the minimalist syntax and reduced middleware components may limit the extensibility and functionality of the API.

In this blog post, we will explore how to implement CRUD (Create, Read, Update, Delete) functionality using Minimal APIs.

A Default Example

In this blog post, I will be using Visual Studio 2022 Community Edition and .NET 7 and the first step would be to start Visual Studio and create a new project, on the Additional Information wizard make sure that you uncheck the Controllers checkbox

Controllers wizard

After the project is created you will find code only in the Program.cs file and it looks like below

// code here ...

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

//code here...

This code sets up a web API endpoint using the ASP.NET Core framework. It sets up a GET endpoint at the URL path “/weatherforecast” that returns an array of weather forecast data.

The endpoint is defined using the MapGet method, which takes two arguments: the URL path to match, and a lambda expression that defines what should happen when the endpoint is called.

Finally, the endpoint is given a name using the WithName method, which is useful for generating documentation and making the endpoint easier to identify in logs. The endpoint is also annotated with OpenAPI metadata (swagger info) using the WithOpenApi method, which can be used to generate API documentation automatically.

The code you have seen above is generated by default when an empty project is created. However, let’s create four new endpoints to retrieve, create, update, and delete data. To accomplish this, we’ll use a simple model called “Student” that looks like the following:

 public class Student
    {
        public int Id { get; set; }
        public string FullName { get; set; }
    }

Getting Data in Minimal API with HttpGet

The first example will be of getting data using an HttpGet request to a minimal API endpoint. To get all students from the database, you need to create a new mapper of type GET, which would look like the below:

app.MapGet("/students", async () =>
{
    var students = await dbContext.Students.ToListAsync();
    return students;
})
.WithName("GetAllStudents")
.WithOpenApi();

This endpoint responds to GET requests at the “/students” URL path and returns a list of all Student objects in the database. The endpoint uses Entity Framework’s ToListAsync method to retrieve the students from the database asynchronously and returns them as the response to the client.

The example above assumes that you have already configured the entity framework core in your application and if you want to learn how to do it you can check out this blog post.

Getting Specific Data in Minimal API with HttpGet/{id}

In the example above you have seen how to load all the data from the database, but in most cases, you will need to load only a single object by using an id as a parameter.

To do that in Minimal API you can use a sample code like below:

app.MapGet("/students/{id}", async (int id) =>
{
    var student = await dbContext.Students.FindAsync(id);

    if (student == null)
    {
        // return 404 Not Found if the student isn't found
        return Results.NotFound();
    }

    return student;
})
.WithName("GetStudentById")
.WithOpenApi();

This endpoint responds to GET requests at the “/students/{id}” URL path, where {id} is a placeholder for the ID of the student to retrieve. When a client sends a GET request to this endpoint with a valid student ID, the code looks up the corresponding student in the database using Entity Framework.

If the student is not found, the endpoint returns a 404 Not Found response using Results.NotFound(). Otherwise, the student is returned as the response to the client.

Creating New Data in Minimal API with HttpPost

To create a new Student you need to send an HttpPost request to the API, for that you need to add a new “mapper” in your code. For HttpPost the mapper type would be Post type

app.MapPost("/students", async (Student student) =>
{
    dbContext.Students.Add(student);
    await dbContext.SaveChangesAsync();

    // return the newly created student with the ID assigned by the database
    return Results.Created($"/students/{student.Id}", student);
})
.WithName("CreateStudent")
.WithOpenApi();

This endpoint responds to POST requests at the “/students” URL path, and creates a new Student object in the database based on the JSON data sent in the request body. The endpoint uses Entity Framework’s Add method to add the new student to the database, and SaveChangesAsync to save the changes.

After the student is created, the endpoint returns a 201 Created response using Results.Created, including the URL of the newly created student in the Location header of the response.

Updating Data in Minimal API with HttpPut

After you add data to the database, lots of time you might want to modify that data. To modify data in the database you can use either HttpPut or HttpPatch, but in this example, I will show you how to use HttpPut to update your data.

app.MapPut("/students/{id}", async (int id, Student updatedStudent) =>
{
    var student = await dbContext.Students.FindAsync(id);

    if (student == null)
        return Results.NotFound();

    // update the properties of the student based on the updatedStudent parameter
    student.FullName = updatedStudent.FullName;
    await dbContext.SaveChangesAsync();

    // return the updated student
    return student;
})
.WithName("UpdateStudent")
.WithOpenApi();

This endpoint responds to PUT requests at the “/students/{id}” URL path, where {id} is a placeholder for the ID of the student to update. When a client sends a PUT request to this endpoint with a valid student ID and an updated Student object in the request body, the code looks up the corresponding student in the database using Entity Framework’s FindAsync method.

If the student is not found, the endpoint returns a 404 Not Found response using Results.NotFound(). Otherwise, the properties of the student are updated based on the updatedStudent parameter, and the changes are saved to the database using dbContext.SaveChangesAsync().

After the student is updated, the endpoint returns the updated student as the response to the client.

Deleting Data in Minimal API with HttpDelete

If you add data by mistake, in the section above you learned how to update the data, but there are cases where you might need to completely remove data from the database, in that case, you can use HttpDelete to remove them. An HttpDelete example would look like the below:

app.MapDelete("/students/{id}", async (int id) =>
{
    var student = await dbContext.Students.FindAsync(id);

    if (student == null)
    {
        // return 404 Not Found if the student isn't found
        return Results.NotFound();
    }

    dbContext.Students.Remove(student);
    await dbContext.SaveChangesAsync();

    // return 204 No Content to indicate that the student was deleted
    return Results.NoContent();
})
.WithName("DeleteStudent")
.WithOpenApi();

This endpoint responds to DELETE requests at the “/students/{id}” URL path, where {id} is a placeholder for the ID of the student to delete.

After the student is deleted, the endpoint returns a 204 No Content response to the client, indicating that the operation was successful and there is no response body.

Swagger Overview

If you add all APIs to your project and run it, the swagger will look like the below:

Swagger UI

Image by rawpixel.com on Freepik


Enjoyed this post? Subscribe to my YouTube channel for more great content. Your support is much appreciated. Thank you!


Check out my Udemy profile for more great content and exclusive learning resources! Thank you for your support.
Ervis Trupja - Udemy



Enjoyed this blog post? Share it with your friends and help spread the word! Don't keep all this knowledge to yourself.