Minimal APIs in ASP.NET: Your Express Lane to Web Magic
The Restaurant Analogy
Imagine you own a tiny food truck instead of a big fancy restaurant. You don’t need a huge kitchen, lots of staff, or complicated systems. You just need:
- A window to take orders
- A simple menu
- Quick hands to make food
That’s Minimal APIs! They’re the food truck of ASP.NET web development. Simple, fast, and gets the job done without all the fancy stuff.
What is a Minimal API?
Think of building a LEGO house. The regular way (Controllers) means you need lots of special pieces, instruction books, and time. Minimal APIs are like building with just the basic bricks - simpler and quicker!
The Old Way vs The New Way
Old Way (Controllers): Like writing a long letter with formal language
[ApiController]
[Route("[controller]")]
public class HelloController
: ControllerBase
{
[HttpGet]
public string Get()
{
return "Hello World!";
}
}
New Way (Minimal API): Like sending a quick text message
var app = WebApplication
.CreateBuilder(args)
.Build();
app.MapGet("/hello",
() => "Hello World!");
app.Run();
See how much shorter? Same result, fewer words!
Route Handlers: Your Order Takers
A route handler is like a waiter at your food truck window. When someone asks for something (visits a URL), the handler responds.
graph TD A["Customer visits /pizza"] --> B["Route Handler"] B --> C[Returns: Here's your pizza!]
Different Types of Handlers
Just like a waiter can take orders, serve food, or clean up, handlers can do different things:
| Action | HTTP Method | Example |
|---|---|---|
| Get something | GET | Show menu |
| Send something | POST | Place order |
| Update something | PUT | Change order |
| Remove something | DELETE | Cancel order |
Simple Handler Examples
// GET - Ask for something
app.MapGet("/menu",
() => "Pizza, Burger, Tacos");
// POST - Send something new
app.MapPost("/order",
() => "Order received!");
// PUT - Change something
app.MapPut("/order/1",
() => "Order updated!");
// DELETE - Remove something
app.MapDelete("/order/1",
() => "Order cancelled!");
Route Parameters: The Magic Blanks
Route parameters are like fill-in-the-blank questions. You leave a spot empty, and someone fills it in!
Example: Greeting by Name
Instead of making separate routes for every person:
// BAD - Don't do this!
app.MapGet("/hello/john", ...);
app.MapGet("/hello/mary", ...);
app.MapGet("/hello/bob", ...);
Use a parameter (blank space):
// GOOD - One route, many names!
app.MapGet("/hello/{name}",
(string name) =>
quot;Hello, {name}!");
Now /hello/John says “Hello, John!”
And /hello/Sarah says “Hello, Sarah!”
Multiple Parameters
You can have many blanks:
app.MapGet("/user/{id}/post/{postId}",
(int id, int postId) =>
quot;User {id}, Post {postId}");
Visiting /user/5/post/42 returns “User 5, Post 42”
graph TD A["/user/{id}/post/{postId}"] --> B["id = 5"] A --> C["postId = 42"] B --> D["User 5, Post 42"] C --> D
Route Groups: Organizing Your Menu
Imagine your food truck menu has sections:
- Burgers: Cheeseburger, Veggie Burger
- Drinks: Cola, Water, Juice
Route Groups work the same way! They organize related routes together.
Without Groups (Messy)
app.MapGet("/burgers", ...);
app.MapGet("/burgers/cheese", ...);
app.MapGet("/burgers/veggie", ...);
app.MapGet("/drinks", ...);
app.MapGet("/drinks/cola", ...);
With MapGroup (Organized!)
var burgers = app.MapGroup("/burgers");
burgers.MapGet("/",
() => "All burgers");
burgers.MapGet("/cheese",
() => "Cheeseburger");
burgers.MapGet("/veggie",
() => "Veggie burger");
var drinks = app.MapGroup("/drinks");
drinks.MapGet("/",
() => "All drinks");
drinks.MapGet("/cola",
() => "Cola");
Both do the same thing, but the grouped version is cleaner!
graph TD A["/burgers"] --> B["/burgers/"] A --> C["/burgers/cheese"] A --> D["/burgers/veggie"] E["/drinks"] --> F["/drinks/"] E --> G["/drinks/cola"]
MapGroup: The Super Organizer
MapGroup is like a folder on your computer. It groups related things together and gives them a shared starting path.
Why Use MapGroup?
- Less Typing: Don’t repeat
/api/productsevery time - Easy to Find: Related routes stay together
- Share Settings: Apply rules to all routes at once
Real Example: Pet Store API
var api = app.MapGroup("/api");
var cats = api.MapGroup("/cats");
cats.MapGet("/",
() => "List all cats");
cats.MapGet("/{id}",
(int id) => quot;Cat #{id}");
cats.MapPost("/",
() => "Added a cat!");
var dogs = api.MapGroup("/dogs");
dogs.MapGet("/",
() => "List all dogs");
dogs.MapGet("/{id}",
(int id) => quot;Dog #{id}");
This creates:
/api/cats- All cats/api/cats/5- Cat #5/api/dogs- All dogs/api/dogs/3- Dog #3
Parameter Binding: The Smart Reader
Parameter binding is like having a smart assistant who reads customer orders and understands exactly what they want!
ASP.NET looks at your request and automatically fills in the values for you.
Where Can Values Come From?
| Source | What It Is | Example |
|---|---|---|
| Route | The URL path | /user/5 |
| Query String | After the ? |
?page=2 |
| Body | Hidden data | JSON payload |
| Header | Extra info | Authorization |
graph LR A["Request"] --> B["Route: /user/5"] A --> C["Query: ?name=Jo"] A --> D["Body: JSON data"] B --> E["Automatic Binding"] C --> E D --> E E --> F["Your Handler Gets Values!"]
Query String Binding: The Question Asker
Query strings are like questions at the end of a URL. They come after the ? mark.
Example URL
/search?keyword=pizza&limit=10
↑ ↑
Question 1 Question 2
Using Query Strings
app.MapGet("/search",
(string keyword, int limit) =>
quot;Searching for '{keyword}', " +
quot;showing {limit} results");
When someone visits /search?keyword=pizza&limit=10, they get:
“Searching for ‘pizza’, showing 10 results”
Optional Query Parameters
Sometimes people don’t fill in everything. Use ? to make it optional:
app.MapGet("/products",
(string? category,
int? page) =>
{
var cat = category ?? "all";
var p = page ?? 1;
return quot;Category: {cat}, " +
quot;Page: {p}";
});
/products→ Category: all, Page: 1/products?category=toys→ Category: toys, Page: 1/products?page=3→ Category: all, Page: 3
Request Body Binding: The Hidden Message
Sometimes customers send you a detailed order - not just a few words, but a whole message! That’s the request body.
The Order Slip Analogy
Think of it like filling out an order form:
Name: John
Item: Large Pizza
Topping: Pepperoni
Address: 123 Main St
In code, we use a class to define what the order looks like:
// The order form template
public class Order
{
public string Name { get; set; }
public string Item { get; set; }
public string Topping { get; set; }
}
// Reading the order
app.MapPost("/orders",
(Order order) =>
quot;Hi {order.Name}! " +
quot;One {order.Item} with " +
quot;{order.Topping} coming up!");
The customer sends JSON:
{
"name": "John",
"item": "Large Pizza",
"topping": "Pepperoni"
}
And you get: “Hi John! One Large Pizza with Pepperoni coming up!”
graph TD A["Customer sends JSON"] --> B["ASP.NET reads it"] B --> C["Creates Order object"] C --> D["Your handler uses it"] D --> E["Response: Hi John!..."]
Putting It All Together: The Complete Food Truck
Let’s build a mini food truck API using everything we learned:
var builder = WebApplication
.CreateBuilder(args);
var app = builder.Build();
// Route Group for all menu items
var menu = app.MapGroup("/menu");
// GET all items
menu.MapGet("/",
() => new[] {
"Pizza",
"Burger",
"Tacos"
});
// GET one item by name (parameter)
menu.MapGet("/{item}",
(string item) =>
quot;You selected: {item}");
// Search with query string
app.MapGet("/search",
(string? q, int? limit) =>
{
var query = q ?? "";
var max = limit ?? 10;
return quot;Searching '{query}' " +
quot;(max {max})";
});
// Create order with body
app.MapPost("/order",
(Order order) =>
quot;Order for {order.Name}: " +
quot;{order.Item}");
app.Run();
public class Order
{
public string Name { get; set; }
public string Item { get; set; }
}
Quick Reference Card
| Concept | What It Does | Example |
|---|---|---|
| Minimal API | Simple web API | app.MapGet(...) |
| Route Handler | Responds to requests | () => "Hello" |
| Route Parameter | Dynamic URL parts | /{id} |
| MapGroup | Organizes routes | app.MapGroup("/api") |
| Query String | URL questions | ?page=2 |
| Body Binding | JSON to object | (Order o) |
You Did It!
You just learned how to:
- Create simple APIs without all the fuss
- Handle different types of requests
- Use parameters to make flexible routes
- Organize routes into groups
- Read data from URLs and request bodies
Minimal APIs are your new superpower! They’re perfect for:
- Quick prototypes
- Small services
- Learning web development
- When you want simplicity
Now go build something amazing! Your food truck is ready to serve the web!
