Minimal APIs in ASP.NET Core

Ujwal WatguleUjwal Watgule
3 min read

Introduction

Minimal APIs, introduced in .NET 6, provide a lightweight approach to building HTTP APIs with minimal setup and configuration. They simplify the development of microservices and small APIs by reducing boilerplate code and focusing on the essentials. This guide will walk you through the concepts, advantages, and implementation of Minimal APIs in ASP.NET Core.

Why Minimal APIs?

  • Simplified Syntax: Write less code to achieve the same functionality.

  • Performance: Optimized for high-performance scenarios.

  • Quick Start: Ideal for small, lightweight, and rapid-development projects.

  • Microservices-Friendly: Perfect for building modular, focused APIs.

Key Features

  1. No Startup.cs or Controller Classes: Everything can be handled in Program.cs.

  2. Direct Mapping: Define routes directly in the code.

  3. Integrated Dependency Injection.

  4. OpenAPI/Swagger Support.

  5. Middleware Integration.

Setting Up a Minimal API Project

Prerequisites:

  • .NET SDK 6.0 or later

Steps:

  1. Create a New Project:

  2. dotnet new web -n MinimalApiDemo

  3. cd MinimalApiDemo

  4. Update Program.cs: Minimal APIs are defined in the Program.cs file.

Code Walkthrough

Here’s a step-by-step example to create a basic CRUD API for managing products.

1. Define the Model

Create a Product model in the Models folder:

public class Product

{

public int Id { get; set; }

public string Name { get; set; } = string.Empty;

public decimal Price { get; set; }

}

2. Configure Dependency Injection

Simulate a database using an in-memory list in Program.cs:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container

builder.Services.AddSingleton<List<Product>>();

var app = builder.Build();

3. Define Endpoints

Add endpoints to handle CRUD operations:

// GET all products

app.MapGet("/products", (List<Product> products) => Results.Ok(products));

// GET product by ID

app.MapGet("/products/{id}", (int id, List<Product> products) =>

{

var product = products.FirstOrDefault(p => p.Id == id);

return product != null ? Results.Ok(product) : Results.NotFound();

});

// POST create a new product

app.MapPost("/products", (Product product, List<Product> products) =>

{

product.Id = products.Count > 0 ? products.Max(p => p.Id) + 1 : 1;

products.Add(product);

return Results.Created($"/products/{product.Id}", product);

});

// PUT update a product

app.MapPut("/products/{id}", (int id, Product updatedProduct, List<Product> products) =>

{

var product = products.FirstOrDefault(p => p.Id == id);

if (product == null) return Results.NotFound();

product.Name = updatedProduct.Name;

product.Price = updatedProduct.Price;

return Results.NoContent();

});

// DELETE a product

app.MapDelete("/products/{id}", (int id, List<Product> products) =>

{

var product = products.FirstOrDefault(p => p.Id == id);

if (product == null) return Results.NotFound();

products.Remove(product);

return Results.NoContent();

});

4. Add Middleware

Add Swagger for API documentation:

// Enable Swagger

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())

{

app.UseSwagger();

app.UseSwaggerUI();

}

app.UseHttpsRedirection();

5. Run the Application

Start the application and test the endpoints:

dotnet run

Access Swagger UI at: https://localhost:<port>/swagger

Advanced Features

1. Input Validation

Use FluentValidation for input validation:

builder.Services.AddScoped<IValidator<Product>, ProductValidator>();

app.MapPost("/products", async (Product product, IValidator<Product> validator, List<Product> products) =>

{

var validationResult = await validator.ValidateAsync(product);

if (!validationResult.IsValid)

{

return Results.BadRequest(validationResult.Errors);

}

product.Id = products.Count > 0 ? products.Max(p => p.Id) + 1 : 1;

products.Add(product);

return Results.Created($"/products/{product.Id}", product);

});

2. Authentication and Authorization

Add JWT-based authentication:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

.AddJwtBearer(options =>

{

options.TokenValidationParameters = new TokenValidationParameters

{

ValidateIssuer = true,

ValidateAudience = true,

ValidateLifetime = true,

ValidateIssuerSigningKey = true,

IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSecretKey"))

};

});

app.UseAuthentication();

app.UseAuthorization();

app.MapGet("/secure-products", [Authorize] (List<Product> products) => Results.Ok(products));

3. CORS Support

Enable Cross-Origin Resource Sharing:

builder.Services.AddCors(options =>

{

options.AddPolicy("AllowAll", policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

});

app.UseCors("AllowAll");

Conclusion

Minimal APIs in ASP.NET Core provide a streamlined approach to building lightweight APIs with minimal overhead. They are perfect for small-scale applications, microservices, or scenarios where simplicity is paramount. By integrating advanced features like authentication, validation, and middleware, Minimal APIs can be extended to handle complex use cases effectively.

References

  1. Microsoft Documentation: Minimal APIs

  2. ASP.NET Core Minimal APIs

  3. FluentValidation Documentation

  4. JWT Authentication in ASP.NET Core

  5. Enable CORS in ASP.NET Core


0
Subscribe to my newsletter

Read articles from Ujwal Watgule directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ujwal Watgule
Ujwal Watgule