Skip to content

ASP.NET Core minimal APIs: routes and results

November 4, 2026 · 1 min read

You map an endpoint with app.MapGet or app.MapPost, group shared paths with MapGroup, and return Results.Ok, Results.Created or Results.NotFound to pick the status code.

A small books API

Create a project with dotnet new web, then replace Program.cs with this:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

List<Book> books =
[
    new(1, "Dune"),
    new(2, "Emma"),
];

var group = app.MapGroup("/books");

group.MapGet("/", () => books);

group.MapGet("/{id:int}", (int id) =>
    books.FirstOrDefault(b => b.Id == id) is Book book
        ? Results.Ok(book)
        : Results.NotFound());

group.MapPost("/", (Book book) =>
{
    books.Add(book);
    return Results.Created($"/books/{book.Id}", book);
});

app.Run();

record Book(int Id, string Title);

Start it with dotnet run, then call it with curl (use the port it prints):

curl http://localhost:5000/books
# [{"id":1,"title":"Dune"},{"id":2,"title":"Emma"}]

curl http://localhost:5000/books/2
# {"id":2,"title":"Emma"}

curl -i -X POST http://localhost:5000/books \
  -H "Content-Type: application/json" \
  -d '{"id":3,"title":"Ulysses"}'
# HTTP/1.1 201 Created
# Location: /books/3
# {"id":3,"title":"Ulysses"}

GET /books/9 returns 404.

How it works

  • MapGroup("/books") is a route group: every endpoint mapped on group starts with /books, so "/" means GET /books.
  • {id:int} is a route parameter with a constraint. It fills the int id parameter, and /books/abc doesn't match, so it gets a 404.
  • A handler that returns a plain object, like the list, sends JSON with 200 OK.
  • Results methods choose the status. Created also sets the Location header.
  • Book book is a record, so it is read from the JSON body. JSON names match property names whatever their case.

Common mistake

Sending a POST without a content type. Without -H "Content-Type: application/json", the body isn't read as JSON and you get 415 Unsupported Media Type. Add the header.

Another one: putting the record before the top-level code. C# wants type declarations after it, so keep record Book at the bottom of Program.cs.

Takeaway

Group your endpoints with MapGroup, map each method with MapGet or MapPost, and return Results when the status code matters.

More on C# & .NET