Minimal REST API using dotnet core

Vikas Sharma
Null Exception
Published in
3 min readOct 17, 2021

After reading about Top-level statements in C# 9, I became curious about the use cases for the same. To my surprise, Microsoft has already taken the feature to the next level in .Net 6.

It turns out it is possible now to create a lightweight full-fledged REST API(CRUD operation) using a single file without having any class like the Node Js.

Lightweight

I explored more to find out what all can be possible with this new feature.

Destination

  • I should be able to set up the development environment without any hassle.
  • I should be able to create CRUD API without creating any controller class or any class for that matter.

Journey

Setting up the development environment

Download and install .Net SDK 6.0.100-rc.1 (at the time of writing this article) or Visual Studio 2022. I am using .Net SDK and Visual Studio Code for this article.

Setting up the database

We just need a SQL Server database. Run the script to generate the database and schema.

Create database TodoDb;
use TodoDb;
Create Table Todo
(
Id INT IDENTITY(1,1) NOT NULL,
[Text] NVARCHAR(MAX),
[Status] VARCHAR(100)
)

Generating web project using dotnet CLI

Run the dotnet command dotnet new web -o MiniTodoAPI to generate the Web Project template.

Open the project on Visual Studio Code. The generated template will contain the following files:

|   appsettings.Development.json
| appsettings.json
| MiniTodoAPI.csproj
| Program.cs
\---Properties
launchSettings.json

We will see, that only a single cs file was generated from the template. And we will use the same file, to create the CRUD API.

NuGet packages required

  • Swashbuckle.AspNetCore
  • Dapper
  • Dapper.Contrib
  • System.Data.SqlClient

Creating API

using Dapper;
using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Dapper.Contrib.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<GetConnection>(sp =>
async () => {
string connectionString = sp.GetService<IConfiguration>()["ConnectionString"];
var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
return connection;
});
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapGet("/", () => "Mini TODO API");
app.MapGet("/todos", async (GetConnection connectionGetter) =>
{
using var con = await connectionGetter();
return con.GetAll<ToDo>().ToList();
});
app.MapGet("/todos/{id}", async (GetConnection connectionGetter, int id) =>
{
using var con = await connectionGetter();
return con.Get<ToDo>(id);
});
app.MapDelete("/todos/{id}", async (GetConnection connectionGetter, int id) =>
{
using var con = await connectionGetter();
con.Delete(new ToDo(id,"",""));
return Results.NoContent();
});
app.MapPost("/todos", async (GetConnection connectionGetter, ToDo todo) =>
{
using var con = await connectionGetter();
var id = con.Insert(todo);
return Results.Created($"/todos/{id}", todo);
});
app.MapPut("/todos", async (GetConnection connectionGetter, ToDo todo) =>
{
using var con = await connectionGetter();
var id = con.Update(todo);
return Results.Ok();
});
app.Run();[Table("Todo")]
public record ToDo(int Id, string Text, string Status);
public delegate Task<IDbConnection> GetConnection();

We created a Record ‘ToDo’ instead of class to use as a dto and model. Then we created a delegate that we will use in dependency injection to create the SQL connection. We registered the delegate in the services so that we can get it later via DI. We did swagger configuration by calling its extension method. We used Dapper for CRUD operation in the database instead of EF to keep the things simple. The complete code is written in Program.cs file as top-level statements without any class.

Compile and run Code

Open command shell of VS Code and run the below command:

  • dotnet restore
  • dotnet build
  • dotnet run

Go to https://localhost:5001/swagger/index.html.

Source code

Complete source code can be found on my GitHub repository though it's just one Program file.

Summary

  • Just one file was created
  • Dapper was used for lightweight database connection
  • Used extension methods to Map the URLs
  • DI was used out of the box
  • The experience was similar to node js

--

--