Lesson 31: Building REST APIs with ASP.NET Core
Build production-ready REST APIs using both Minimal APIs and Controller patterns in ASP.NET Core.
What You'll Learn
- • Minimal APIs for lightweight, fast endpoints
- • Controller-based APIs with routing, filters, and model binding
- • Request validation with Data Annotations
- • Proper HTTP status codes and response patterns
🧠 Real-World Analogy
A REST API is like a restaurant menu. The client (customer) makes requests (orders), the server (kitchen) processes them, and responds with data (food). HTTP verbs are the actions: GET = "read the menu," POST = "place an order," PUT = "change my order," DELETE = "cancel my order."
| HTTP Verb | Action | Success Code | Example |
|---|---|---|---|
| GET | Read | 200 OK | GET /api/products |
| POST | Create | 201 Created | POST /api/products |
| PUT | Update | 200 OK | PUT /api/products/1 |
| DELETE | Delete | 204 No Content | DELETE /api/products/1 |
Minimal APIs
Minimal APIs let you define endpoints with just a few lines of code — no controllers, no boilerplate. They're perfect for microservices and simple APIs. ASP.NET Core 8+ makes them even more powerful with route groups and filters.
Minimal API — Todo CRUD
Build a complete CRUD API with Minimal API syntax.
// Program.cs — Minimal API (ASP.NET Core 8+)
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// In-memory data store
var todos = new List<Todo>
{
new(1, "Learn C#", true),
new(2, "Build an API", false),
new(3, "Deploy to Azure", false)
};
int nextId = 4;
// GET all todos
app.MapGet("/api/todos", () => Results.Ok(todos));
// GET by ID
a
...Controller-Based APIs
For larger APIs, controllers provide better organization with routing attributes, action filters, and automatic model binding. The [ApiController] attribute adds automatic validation, binding source inference, and problem details responses.
Controller API — Products with Filtering
Build a controller-based API with query parameters and proper status codes.
using Microsoft.AspNetCore.Mvc;
// Controllers/ProductsController.cs
[ApiController]
[Route("api/[controller]")] // Route: /api/products
public class ProductsController : ControllerBase
{
private static readonly List<Product> _products = new()
{
new Product { Id = 1, Name = "Laptop", Price = 999.99m, Category = "Electronics" },
new Product { Id = 2, Name = "Headphones", Price = 149.99m, Category = "Electronics" },
new Product { Id = 3, Name = "Desk Chair", Price
...Request Validation
Never trust client input. Use Data Annotations to declaratively validate requests. The [ApiController] attribute automatically returns 400 Bad Request with validation errors before your action code even runs.
Request Validation with Data Annotations
Validate API requests with built-in and custom validation attributes.
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
// Model with validation attributes
public class RegisterRequest
{
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email format")]
public string Email { get; set; } = "";
[Required]
[StringLength(50, MinimumLength = 2,
ErrorMessage = "Name must be 2-50 characters")]
public string Name { get; set; } = "";
[Required]
[MinLength(8, Err
...Pro Tip
Use TypedResults in Minimal APIs for compile-time checked return types: app.MapGet("/", () => TypedResults.Ok(data)). This also generates better OpenAPI documentation automatically.
Common Mistakes
- • Returning 200 for everything — use proper status codes (201, 204, 404, 422)
- • Exposing database entities directly — use DTOs to control the API shape
- • Not versioning your API — add
/v1/prefix from day one
Lesson Complete!
You can now build REST APIs with both Minimal and Controller patterns. Next, learn to add middleware, filters, and custom attributes for cross-cutting concerns.
Sign up for free to track which lessons you've completed and get learning reminders.