DEV Community

Cover image for ASP.NET Core Minimal API: A Practical Implementation Guide
M. Oly Mahmud
M. Oly Mahmud

Posted on

3

ASP.NET Core Minimal API: A Practical Implementation Guide

ASP.NET Core Minimal APIs let us create web APIs quickly with less code—like a fast way to build a to-do list app. In this guide, we’ll make a Todo API step by step using .NET 8. It’ll let us add, view, update, and delete tasks. We’ll use a database (SQL Server) in Docker and add Swagger to test it easily. Let’s go, one simple step at a time!


Step 1: Get Our Tools Ready

Before we start, we need these on our computer:

  • .NET 8 SDK: Lets us build .NET apps. We can get it from dotnet.microsoft.com.
  • Docker: Runs SQL Server in a container. We’ll install Docker Desktop from docker.com.
  • Text Editor: We’ll use Visual Studio, VS Code, or anything we like.

Docker Setup: We’ll use Docker Compose to run SQL Server. Here’s what we need later in a file called docker-compose.yml:

services:
  sql-server:
    image: mcr.microsoft.com/mssql/server:2022-latest
    container_name: sql-server
    hostname: sql-server
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_SA_PASSWORD=MySecurePassword123!
    ports:
      - "1433:1433"
    restart: unless-stopped
    networks:
      - sql_network

networks:
  sql_network:
    driver: bridge
Enter fullscreen mode Exit fullscreen mode
  • We’ll save this in our project folder when we’re ready.

Quick Check: Let’s open a terminal (like Command Prompt) and type dotnet --version. If it shows “8.0.xxx,” we’re set!


Step 2: Project Setup

Let’s create a new project for our Todo API.

  1. Open Our Terminal:

    • We’ll go to a folder where we want our project (e.g., cd Documents).
  2. Make the Project:

    • Run the following command:
      dotnet new web -n TodoApp --framework net8.0
    

This makes a TodoApp folder with a basic web app.

  1. Go Inside the Folder:

    • Go to the project directory:
      cd TodoApp
    
  2. What We’ve Got:

    • Here’s the project layout as a tree structure:
      TodoApp/
      ├── Program.cs              # Our main code file where we’ll build the API
      ├── TodoApp.csproj          # A list of what the project needs (like tools)
      └── Properties/
          └── launchSettings.json # Sets how the app runs (like which port)
    
  • This is what we start with after running the command.

Step 3: Add the Tools We Need

Our API needs extra tools to work with a database and show a testing page.

  1. Add Packages:

    • We’ll run these in the terminal:
      dotnet add package Microsoft.EntityFrameworkCore
      dotnet add package Microsoft.EntityFrameworkCore.SqlServer
      dotnet add package Microsoft.EntityFrameworkCore.Tools
      dotnet add package Swashbuckle.AspNetCore
    
  • What they do:
    • EntityFrameworkCore: Talks to the database.
    • SqlServer: Works with SQL Server.
    • Tools: Helps set up the database.
    • Swashbuckle: Adds Swagger, a testing webpage.
  1. Check the Project File:

    • We’ll open TodoApp.csproj. It should look like this:
      <Project Sdk="Microsoft.NET.Sdk.Web">
        <PropertyGroup>
          <TargetFramework>net8.0</TargetFramework>
          <Nullable>enable</Nullable>
          <ImplicitUsings>enable</ImplicitUsings>
        </PropertyGroup>
        <ItemGroup>
          <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
          <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.2" />
          <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.2">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
          </PackageReference>
          <PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
        </ItemGroup>
      </Project>
    
  • This shows all the tools are added with their versions.

Step 4: Start SQL Server with Docker

We need a database to save our to-dos. Let’s use the Docker setup we saw earlier.

  1. Make the Docker File:

    • In the TodoApp folder, we’ll create docker-compose.yml.
    • We’ll copy this in (from Step 1):
      services:
        sql-server:
          image: mcr.microsoft.com/mssql/server:2022-latest
          container_name: sql-server
          hostname: sql-server
          environment:
            - ACCEPT_EULA=Y
            - MSSQL_SA_PASSWORD=MySecurePassword123!
          ports:
            - "1433:1433"
          restart: unless-stopped
          networks:
            - sql_network
    
      networks:
        sql_network:
          driver: bridge
    
  2. Start SQL Server:

    • Run the following command to start the SQL Server container:
      docker-compose up -d
    
  • It runs in the background.
  1. Check It’s Running:

    • Run the following command:
      docker ps
    
  • We should see sql-server. If it’s there, we’re good!

Step 5: Tell the App How to Find the Database

We need to give our app the database’s address and password.

  1. Make a Settings File:

    • We’ll create appsettings.json in the TodoApp folder.
    • We’ll add this:
      {
        "ConnectionStrings": {
          "DefaultConnection": "Server=localhost;Database=TodoDb;User Id=sa;Password=MySecurePassword123!;TrustServerCertificate=True;"
        },
        "Logging": {
          "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
          }
        },
        "AllowedHosts": "*"
      }
    
  • What it does:
    • DefaultConnection: Says “use SQL Server on localhost, database TodoDb, user sa, password from Docker.”

Step 6: Define a To-Do Item

Let’s decide what a to-do looks like.

  1. Make a Models Folder:

    • We’ll create a folder called Models in TodoApp.
  2. Add the Todo File:

    • Inside Models, we’ll create Todo.cs and add:
      namespace TodoApp.Models;
    
      public class Todo
      {
          public int Id { get; set; } // A number for each to-do
          public string Title { get; set; } = string.Empty; // The task, like "Call Mom"
          public bool IsCompleted { get; set; } = false; // Done or not
      }
    
  • This is a simple way to describe a to-do.

Step 7: Connect to the Database

We need a helper to link our app to the database.

  1. Make a Data Folder:

    • We’ll create a folder called Data in TodoApp.
  2. Add the Helper:

    • Inside Data, we’ll create AppDbContext.cs and add:
      using Microsoft.EntityFrameworkCore;
      using TodoApp.Models;
    
      namespace TodoApp.Data;
    
      public class AppDbContext : DbContext
      {
          public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
          public DbSet<Todo> Todos { get; set; } = null!; // Our to-do list in the database
      }
    
  • It connects our app to TodoDb.

Step 8: Build the API

Now, let’s make the API work with all the pieces.

  1. Open Program.cs:

    • We’ll replace everything with:
      using Microsoft.EntityFrameworkCore;
      using TodoApp.Data;
      using TodoApp.Models;
    
      var builder = WebApplication.CreateBuilder(args);
    
      // Connect to the database
      builder.Services.AddDbContext<AppDbContext>(options =>
          options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
    
      // Add Swagger for testing
      builder.Services.AddEndpointsApiExplorer();
      builder.Services.AddSwaggerGen();
    
      var app = builder.Build();
    
      // Show Swagger when testing
      if (app.Environment.IsDevelopment())
      {
          app.UseSwagger();
          app.UseSwaggerUI(options =>
          {
              options.SwaggerEndpoint("/swagger/v1/swagger.json", "Todo API v1");
          });
      }
    
      // Create the database if it’s not there
      using (var scope = app.Services.CreateScope())
      {
          var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
          dbContext.Database.EnsureCreated();
      }
    
      // Add a new to-do
      app.MapPost("/todos", async (AppDbContext db, Todo todo) =>
      {
          db.Todos.Add(todo);
          await db.SaveChangesAsync();
          return Results.Created($"/todos/{todo.Id}", todo);
      });
    
      // Get all to-dos
      app.MapGet("/todos", async (AppDbContext db) =>
      {
          return await db.Todos.ToListAsync();
      });
    
      // Get one to-do
      app.MapGet("/todos/{id}", async (AppDbContext db, int id) =>
      {
          var todo = await db.Todos.FindAsync(id);
          return todo is not null ? Results.Ok(todo) : Results.NotFound();
      });
    
      // Update a to-do
      app.MapPut("/todos/{id}", async (AppDbContext db, int id, Todo updatedTodo) =>
      {
          var todo = await db.Todos.FindAsync(id);
          if (todo is null) return Results.NotFound();
          todo.Title = updatedTodo.Title;
          todo.IsCompleted = updatedTodo.IsCompleted;
          await db.SaveChangesAsync();
          return Results.NoContent();
      });
    
      // Delete a to-do
      app.MapDelete("/todos/{id}", async (AppDbContext db, int id) =>
      {
          var todo = await db.Todos.FindAsync(id);
          if (todo is null) return Results.NotFound();
          db.Todos.Remove(todo);
          await db.SaveChangesAsync();
          return Results.NoContent();
      });
    
      app.Run();
    
  2. What’s Happening:

    • Database: Connects to SQL Server.
    • Swagger: Adds a testing page.
    • Actions: Sets up five things we can do:
      • Add (POST /todos).
      • List all (GET /todos).
      • Get one (GET /todos/{id}).
      • Update (PUT /todos/{id}).
      • Delete (DELETE /todos/{id}).

Step 9: Check How the App Runs

Our app has a file called launchSettings.json that decides where it runs (like on port 5240).

  1. Look at launchSettings.json:

    • We’ll open Properties/launchSettings.json. It looks like this:
      {
        "$schema": "http://json.schemastore.org/launchsettings.json",
        "iisSettings": {
          "windowsAuthentication": false,
          "anonymousAuthentication": true,
          "iisExpress": {
            "applicationUrl": "http://localhost:52287",
            "sslPort": 44350
          }
        },
        "profiles": {
          "http": {
            "commandName": "Project",
            "dotnetRunMessages": true,
            "launchBrowser": true,
            "applicationUrl": "http://localhost:5240",
            "environmentVariables": {
              "ASPNETCORE_ENVIRONMENT": "Development"
            }
          },
          "https": {
            "commandName": "Project",
            "dotnetRunMessages": true,
            "launchBrowser": true,
            "applicationUrl": "https://localhost:7006;http://localhost:5240",
            "environmentVariables": {
              "ASPNETCORE_ENVIRONMENT": "Development"
            }
          },
          "IIS Express": {
            "commandName": "IISExpress",
            "launchBrowser": true,
            "environmentVariables": {
              "ASPNETCORE_ENVIRONMENT": "Development"
            }
          }
        }
      }
    
  2. What This Means:

    • This file was made when we created the project.
    • Profiles: Three ways to start the app:
      • "http": Runs on http://localhost:5240 (plain HTTP).
      • "https": Runs on https://localhost:7006 and http://localhost:5240 (secure and plain options).
      • "IIS Express": Uses a local web server (like in Visual Studio).
    • Port 5240: For HTTP, it uses 5240. That’s where we’ll test it!
    • launchBrowser: Opens our browser when the app starts.

Step 10: Create the Database

The app will make the database when it starts.

  1. Easy Way:

    • The EnsureCreated() line in Program.cs creates TodoDb and a Todos table the first time we run.
  2. Optional Better Way:

    • For a real app, we can use migrations:

      • Install the tool:
        dotnet tool install --global dotnet-ef
      
      • Make a migration:
        dotnet ef migrations add InitialCreate
      
      • Create the database:
        dotnet ef database update
      
      • Remove EnsureCreated() from Program.cs.
  3. Check It:

    • We’ll use SQL Server Management Studio:
    • Connect to localhost, user sa, password MySecurePassword123!.
    • Look for TodoDb.

Step 11: Run and Test the API

Let’s try it out!

  1. Start the App:

    • We’ll type:
      dotnet run --project TodoApp.csproj
    
  1. Open Swagger:

    • We’ll go to http://localhost:5240/swagger in our browser.
    • We’ll see a page with all our API actions.
  2. Play with It:

    • Add a To-Do: We’ll click POST /todos, “Try it out”, and add:
      { "title": "Learn .NET 8", "isCompleted": false }
    

Click “Execute”. We’ll get a new to-do with an ID.

  • List All: We’ll use GET /todos.
  • Get One: We’ll try GET /todos/1 (use our ID).
  • Update: We’ll use PUT /todos/1 with:

      { "title": "Master .NET 8", "isCompleted": true }
    
  • Delete: We’ll use DELETE /todos/1.


Step 12: What We’ve Got

Here’s what’s in our project:

  • Program.cs: Runs the app and defines the API.
  • Models/Todo.cs: Describes a to-do.
  • Data/AppDbContext.cs: Links to the database.
  • appsettings.json: Has the database address.
  • Properties/launchSettings.json: Sets the port (5240 for HTTP).
  • docker-compose.yml: Runs SQL Server.

Wrap-Up

Awesome job! We’ve made a Todo API with .NET 8 Minimal APIs. It’s simple, uses Docker for the database, and has Swagger to test it. Want more? We can add checks for bad input or login stuff later. For now, let’s have fun with our API—happy coding!

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more

👋 Kindness is contagious

If this post resonated with you, feel free to hit ❤️ or leave a quick comment to share your thoughts!

Okay