Two Ways To Create Minimal APIs In .NET 6

Minimal API is a new template that uses all the C# 10 features and .NET 6 to create simple services with less complexity, layers, classes or using the traditional MVC template with controllers. This is inspired by other technologies like node.js, python, and go. 

To create a minimal API, you can use the command dotnet new web in Dotnet CLI, or in Visual Studio 2022 (or higher), there is an empty template that creates the same structure.

All the logic and architecture are on one file, which is Program.cs where you will include the logic, classes, endpoints, and services. 

The template includes an endpoint with helloword example. Thanks to C# 10 features we don't need namespaces or the main method and class.

There are 2 ways to create the endpoints for Minimal APIs. First, using the endpoint methods directly where we have to manually get the services, the response, and parameters. In the following example, it's getting TodoDbContext from RequestServices and it is writing the response using WriteAsJsonAsync.

app.MapGet("/todoitems", async (http) => {
    var dbContext = http.RequestServices.GetService < TodoDbContext > ();
    var todoItems = await dbContext.TodoItems.ToListAsync();
    await http.Response.WriteAsJsonAsync(todoItems);

If you want to return a specific status code and get the parameter, you have to manually set it or get it. In the following example, it returns 400 when the id is not valid and 204 when it updates the record, also it is getting the context (TodoDbContext) from RequestServices again.

app.MapPut("/todoitems/{id}", async (http) => {
    if (!http.Request.RouteValues.TryGetValue("id", out
            var id)) {
        http.Response.StatusCode = 400;
    var dbContext = http.RequestServices.GetService < TodoDbContext > ();
    var todoItem = await dbContext.TodoItems.FindAsync(int.Parse(id.ToString()));
    if (todoItem == null) {
        http.Response.StatusCode = 404;
    var inputTodoItem = await http.Request.ReadFromJsonAsync < TodoItem > ();
    todoItem.IsCompleted = inputTodoItem.IsCompleted;
    await dbContext.SaveChangesAsync();
    http.Response.StatusCode = 204;

The second way is to use the attributes and results object. This looks very similar to the traditional APIs using MVC and controllers. [FromServices] get the services in the configuration.

app.MapGet("/todoitems/{id}", async ([FromServices] TodoDbContext dbContext, int id) => {
    var todoItem = await dbContext.TodoItems.FindAsync(id);
    if (todoItem == null) {
        return Results.NotFound();
    return Results.Ok(todoItem);

To use results and the FromServices attribute you have to add using Microsoft.AspNetCore.Mvc; in the file.

Full code: Mteheran/DotnetMinimalApi (

Both methods are correct, but finally, if you want to use something easier to read, the second way, where we use decorators and result functions, is much better.