Get started with minimal API for .NET 6
Tags: dotnet, csharp, tutorial, webdev
Published: 2021-11-08 17:04:00

---
title: Get started with minimal API for .NET 6
published: true
description: This is a series on web development with minimal API using .NET 6.
tags: dotnet, csharp, tutorial, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1qm4z6rbo9kt22ia8id.png
---

> TLDR; Using minimal API, you can create a Web API in just 4 lines of code by leveraging new features like top-level statements and more.

## Why Minimal API

There are many reasons for wanting to create an API in a few lines of code:

- **Create a prototype**. Sometimes you want a quick result, a prototype, something to discuss with your colleagues. Having something up and running quickly enables you to quickly do changes to it until you get what you want.
- **Progressive enhancement**. You might not want all the "bells and whistles" to start with but you may need them over time. Minimal API makes it easy to gradually add what you need, when you need it.

## Learn more

Check out these LEARN modules on learning to use minimal API
- [Your first minimal API + Swagger](https://docs.microsoft.com/learn/modules/build-web-api-minimal-api?wt.mc_id=academic-0000-chnoring)
- [minimal API with Entity Framework](https://docs.microsoft.com/learn/modules/build-web-api-minimal-database?wt.mc_id=academic-0000-chnoring)
- [minimal API with React](https://docs.microsoft.com/learn/modules/build-web-api-minimal-spa?wt.mc_id=academic-0000-chnoring)

## How is it different from a normal Web API?

There are a few differences:

- **Less files**. _Startup.cs_ isn't there anymore, only _Program.cs_ remains.
- **Top level statements and implicit global usings**. Because it's using top level statements, `using` and `namespace` are gone as well, so this code:

   ```csharp
   using System;
   namespace Application
   {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello World!");
            }
        }
   }
   ```

   is now this code:

   ```csharp
   Console.WriteLine("Hello World!");
   ```

   

- **Routes** Your routes aren't mapped to controller classes but rather setup with a `Map[VERB]` function, like you see above with `MapGet()` which takes a route and a function to invoke when said route is hit.

## Your first API

To get started with minimal API, you need to make sure that .NET 6 is installed and then you can scaffold an API via the command line, like so:

```bash
dotnet new web -o MyApi -f net6.0
```

Once you run that, you get a folder _MyApi_ with your API in it.

What you get is the following code in _Program.cs_:

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

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/", () => "Hello World!");

app.Run();
```

To run it, type `dotnet run`. A little difference here with the port is that it assumes random ports in a range rather than 5000/5001 that you may be used to. You can however configure the ports as needed. Learn more on this [docs page](https://docs.microsoft.com/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0#working-with-ports)

## Explaining the parts

Ok so you have a minimal API, what's going on with the code?

### Creating a builder

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

On the first line you create a `builder` instance. `builder` has a `Services` property on it, so you can add capabilities on it like Swagger Cors, Entity Framework and more. Here's an example where you set up Swagger capabilities (this needs install of the Swashbuckle NuGet to work though):

```csharp
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todo API", Description = "Keep track of your tasks", Version = "v1" });
    });
```

### Creating the app instance

Here's the next line:

```csharp
var app = builder.Build();
```

Here we create an `app` instance. Via the `app` instance, we can do things like:

- Starting the app, `app.Run()`
- Configuring routes, `app.MapGet()`
- Configure middleware, `app.UseSwagger()` 

### Defining the routes

With the following code, a route and route handler is configured:

```csharp
app.MapGet("/", () => "Hello World!");
```

The method `MapGet()` sets up a new route and takes the route "/" and a route handler, a function as the second argument `() => "Hello World!"`.

### Starting the app

To start the app, and have it serve requests, the last thing you do is call `Run()` on the `app` instance like so:

```csharp
app.Run();
```

## Add routes

To add an additional route, we can type like so:

```csharp
public record Pizza(int Id, string Name); 
app.MapGet("/pizza", () => new Pizza(1, "Margherita"));
```

Now you have code that looks like so:

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

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/pizza", () => new Pizza(1, "Margherita"));
app.MapGet("/", () => "Hello World!");

public record Pizza(int Id, string Name); 

app.Run();


```

Where you to run this code, with `dotnet run` and navigate to `/pizza` you would get a JSON response:

```json
{
  "pizza" : {
    "id" : 1,
    "name" : "Margherita"
  }
}
```

## Example app

Let's take all our learnings so far and put that into an app that supports GET and POST and lets also show easily you can use query parameters:

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

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

var pizzas = new List<Pizza>(){
   new Pizza(1, "Margherita"),
   new Pizza(2, "Al Tonno"),
   new Pizza(3, "Pineapple"),
   new Pizza(4, "Meat meat meat")
};

app.MapGet("/", () => "Hello World!");
app.MapGet("/pizzas/{id}", (int id) => pizzas.SingleOrDefault(pizzas => pizzas.Id == id));
app.MapGet("/pizzas", (int ? page, int ? pageSize) => {
    if(page.HasValue && pageSize.HasValue) 
    {
        return pizzas.Skip((page.Value -1) * pageSize.Value).Take(pageSize.Value);
    } else {
        return pizzas;
    }
});
app.MapPost("/pizza", (Pizza pizza) => pizzas.Add(pizza));

app.Run();

public record Pizza(int Id, string Name);

```

Run this app with `dotnet run`

In your browser, try various things like:

- "http://localhost:{PORT}/pizzas", should give you all pizzas back
- "http://localhost:{PORT}/pizzas?page=1&pageSize=2", should give you the two first pizzas. See how the query parameters are working for you.
- "http://localhost:{PORT}/pizzas/2", should give you the "Al Tonno" pizza back. Here you have the `{id}` matching the 2 and thereby it filters down on the one item that matches.

## Learn more

Check out these LEARN modules on learning to use minimal API
- [Your first minimal API + Swagger](https://docs.microsoft.com/learn/modules/build-web-api-minimal-api?wt.mc_id=academic-0000-chnoring)
- [minimal API with Entity Framework](https://docs.microsoft.com/learn/modules/build-web-api-minimal-database?wt.mc_id=academic-0000-chnoring)
- [minimal API with React](https://docs.microsoft.com/learn/modules/build-web-api-minimal-spa?wt.mc_id=academic-0000-chnoring)