# Your First Minimal API

A minimal API maps each address and method straight to a lambda in Program.cs, with MapGet, MapPost, MapPut and MapDelete. The lambda's parameters come from the route and the body, and Results.NotFound(), Results.Created() and friends choose the status code.

Apprentice · ASP.NET Core · REST API · Updated November 3, 2026

## After this lesson you can

- Map GET, POST, PUT and DELETE endpoints to lambdas in a minimal API
- Return a status code with Results, such as Results.NotFound() or Results.Created()

## Key takeaways

- A minimal API maps each method and address to a lambda in `Program.cs` with `MapGet`, `MapPost`, `MapPut` or `MapDelete`.
- A parameter such as `int id` gets its value from `{id}` in the address; a class parameter such as `Todo todo` comes from the JSON body.
- Return an object or a list, and it's sent as JSON with `200 OK`.
- Return a `Results` method, such as `Results.NotFound()`, `Results.Created(...)` or `Results.NoContent()`, to answer with a different status code.
- ASP.NET Core writes JSON property names in camelCase, so `Title` becomes `title`.

A **Web API** is a web app that answers with **data** instead of pages. A browser asks an MVC app for `/products` and gets back HTML to show. A program asks an API for `/api/products` and gets back JSON to use. Mobile apps, JavaScript in web pages, and other servers are all clients of APIs.

ASP.NET Core has two ways to build one. This lesson shows the smallest: a **minimal API**.

## Creating the project

In Visual Studio, create a new project from the **ASP.NET Core Web API** template, and on the last page **clear** the **Use controllers** box. (In a terminal: `dotnet new webapi -o TodoApi`.) The template's `Program.cs` holds a sample weather forecast; replace it with the to-do list below.

## A to-do list API

Here's a whole API in `Program.cs`: a to-do list kept in memory, with an endpoint for each thing a client can do.

```csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

// The to-do list, kept in memory: it starts again whenever the app restarts.
List<Todo> todos = new List<Todo>
{
    new Todo { Id = 1, Title = "Buy milk", Done = false },
    new Todo { Id = 2, Title = "Call the dentist", Done = true }
};

app.MapGet("/todos", () => todos);

app.MapGet("/todos/{id}", (int id) =>
{
    Todo? todo = todos.Find(t => t.Id == id);
    if (todo == null)
    {
        return Results.NotFound();
    }
    return Results.Ok(todo);
});

app.MapPost("/todos", (Todo todo) =>
{
    todo.Id = todos.Count == 0 ? 1 : todos.Max(t => t.Id) + 1;
    todos.Add(todo);
    return Results.Created($"/todos/{todo.Id}", todo);
});

app.MapPut("/todos/{id}", (int id, Todo changed) =>
{
    Todo? todo = todos.Find(t => t.Id == id);
    if (todo == null)
    {
        return Results.NotFound();
    }
    todo.Title = changed.Title;
    todo.Done = changed.Done;
    return Results.Ok(todo);
});

app.MapDelete("/todos/{id}", (int id) =>
{
    int removed = todos.RemoveAll(t => t.Id == id);
    return removed == 0 ? Results.NotFound() : Results.NoContent();
});

app.Run();

public class Todo
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public bool Done { get; set; }
}
```

## Endpoints

Each `Map...` call creates an **endpoint**: a method and an address, joined to the code that answers it.

| Call | Answers |
|---|---|
| `app.MapGet("/todos", ...)` | `GET /todos` |
| `app.MapGet("/todos/{id}", ...)` | `GET /todos/2`, `GET /todos/7`, … |
| `app.MapPost("/todos", ...)` | `POST /todos` |
| `app.MapPut("/todos/{id}", ...)` | `PUT /todos/2` |
| `app.MapDelete("/todos/{id}", ...)` | `DELETE /todos/2` |

The code that answers is a **lambda**, like the ones you gave to LINQ. ASP.NET Core fills in its parameters for you:

- **`int id`** comes from the `{id}` in the address, converted to an `int`: `/todos/2` gives `id = 2`.
- **`Todo todo`** comes from the request's JSON body, turned into a `Todo` object. That's called **model binding**, as in MVC.

Whatever the lambda returns becomes the response. Return a list or an object, as the first `MapGet` does, and it's sent as JSON with `200 OK`.

## Choosing the status code with Results

When `200 OK` isn't the right answer, return one of the **`Results`** methods instead:

| Return | Answers |
|---|---|
| `Results.Ok(todo)` | `200 OK`, with the to-do as JSON, as the `MapPut` answers with the changed to-do |
| `Results.Created("/todos/3", todo)` | `201 Created`, with a `Location` header and the new to-do |
| `Results.NoContent()` | `204 No Content`: done, with nothing to send back, as after a `DELETE` |
| `Results.NotFound()` | `404 Not Found` |
| `Results.BadRequest("Give the to-do a title")` | `400 Bad Request`, with a message |

## Trying it

Run the app with **Ctrl+F5**, and send these requests from the project's `.http` file (use your project's own address):

```http
@HostAddress = http://localhost:5248

GET {{HostAddress}}/todos/9

###

POST {{HostAddress}}/todos
Content-Type: application/json

{
  "title": "Water the plants",
  "done": false
}

###
```

The first answers `404 Not Found`: there's no to-do 9. The second answers:

```http
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: /todos/3

{
  "id": 3,
  "title": "Water the plants",
  "done": false
}
```

JSON property names start with a small letter (`title`, `done`): ASP.NET Core converts C#'s `Title` to the *camelCase* that JavaScript clients expect, and back again when it reads a body.

Stop the app and start it again, and the new to-do is gone: the list only lives in memory. Real APIs keep their data in a database, as the next topic's do.

## Check yourself

2 questions to try on the lesson page.

## So what

A minimal API is an address, a method and a lambda, repeated for each thing a client can do. It's the quickest way to put data on the web, and the same ideas, endpoints, model binding and status codes, carry straight over to controllers.

## Key terms

- [Web API](https://www.ask-codey.com/glossary/web-api)
- Minimal API
- [Endpoint](https://www.ask-codey.com/glossary/endpoint-rest-api)
- MapGet and MapPost
- Results and TypedResults

## Cheat sheets

- [Your First Minimal API](https://www.ask-codey.com/cheat-sheets/minimal-apis-your-first-minimal-api-cheat-sheet)

Source: https://www.ask-codey.com/lessons/minimal-apis-your-first-minimal-api
