Minimal REST API using dotnet core
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.
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