Minimal API

Маршрутизація в ASP.NET Core: Основи

Маршрутизація (Routing) — це фундаментальний механізм будь-якого веб-фреймворку. Вона відповідає за аналіз вхідного HTTP-запиту (наприклад, GET /users/1) та виклик відповідної ділянки коду (обробника) для формування відповіді.

Маршрутизація в ASP.NET Core: Основи

Маршрутизація (Routing) — це фундаментальний механізм будь-якого веб-фреймворку. Вона відповідає за аналіз вхідного HTTP-запиту (наприклад, GET /users/1) та виклик відповідної ділянки коду (обробника) для формування відповіді.

У цьому розділі ми розберемо анатомію маршрутизації в ASP.NET Core Minimal APIs, навчимося створювати кінцеві точки (Endpoints) та працювати з параметрами маршрутів.

Що таке маршрутизація і навіщо вона потрібна?

Уявіть великий офісний центр. Коли ви заходите всередину, ви бачите турнікет і рецепцію зі списком компаній на різних поверхах. HTTP-запит — це ви. Маршрутизатор (Router) — це рецепція. Вона дивиться куди вам треба (/sales або /support) і направляє вас до потрібного кабінету (обробника).

Без маршрутизації нам довелося б вручну писати складний код з купою if/else, щоб аналізувати URL кожного запиту і вирішувати, що робити.

В ASP.NET Core маршрутизація складається з двох основних етапів (Middleware):

  1. EndpointRoutingMiddleware (UseRouting()): Знаходить кінцеву точку, яка відповідає запиту.
  2. EndpointMiddleware (UseEndpoints()): Виконує код (делегат) знайденої кінцевої точки.
У сучасних додатках Minimal APIs вам рідко доводиться викликати UseRouting та UseEndpoints вручну, оскільки клас WebApplication автоматично налаштовує їх для вас.

Аналізатор кінцевих точок (Endpoint)

Кінцева точка (Endpoint) складається з трьох основних речей:

  1. HTTP-метод (GET, POST, PUT, DELETE тощо).
  2. Шаблон маршруту (наприклад, / або /users/{id}).
  3. Обробник (функція, яка виконається).

Створення базових кінцевих точок

Для визначення маршрутів ми використовуємо методи об'єкта app (інстанс WebApplication), такі як MapGet, MapPost, MapPut, MapDelete.

Розглянемо найпростіший приклад:

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

app.MapGet("/", () => "Головна сторінка");
app.MapGet("/about", () => "Сторінка про компанію");

app.Run();

Анатомія коду:

  • Ми створили дві кінцеві точки:
    • Перша реагує на HTTP GET запит за кореневою адресою / і повертає рядок "Головна сторінка".
    • Друга реагує на HTTP GET запит за адресою /about і повертає "Сторінка про компанію".
  • Обробником тут виступає звичайна лямбда-функція () => ....

Повернення об'єктів (JSON Serializing)

Сучасні API рідко повертають просто текст. Зазвичай це структуровані дані у форматі JSON. ASP.NET Core Minimal APIs робить перетворення об'єкта в JSON автоматично!

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

app.MapGet("/user", () => new Person("John Doe", 30));

app.Run();

record class Person(string Name, int Age);

Анатомія коду:

  • Ми створили record class Person.
  • У маршруті /user ми просто повертаємо new Person(...).
  • Магія під капотом: Фреймворк бачить, що ми повертаємо об'єкт (не рядок), автоматично серіалізує його в JSON та встановлює HTTP-заголовок Content-Type: application/json.

Результат запиту:

{
    "name": "John Doe",
    "age": 30
}

Базові CRUD операції (REST)

Використовуючи різні HTTP-методи (MapGet, MapPost, MapPut, MapDelete), ми можемо побудувати повноцінне RESTful API:

Program.cs
var app = WebApplication.Create();

app.MapGet("/items", () => "Отримання списку");
app.MapPost("/items", (Item item) => Results.Created($"/items/{item.Id}", item));
app.MapPut("/items/{id}", (int id, Item item) => Results.NoContent());
app.MapDelete("/items/{id}", (int id) => Results.Ok());

app.Run();

public record Item(int Id, string Name);

Анатомія коду:

  • MapGet("/items"): Обробляє отримання всіх елементів.
  • MapPost("/items"): Дані з тіла запиту (Request Body) автоматично десеріалізуються (JSON -> об'єкт) і передаються в параметр Item item.
  • MapPut та MapDelete: Містять у шляху параметр {id}, про який ми поговоримо детальніше нижче.
  • Results.Created, Results.Ok, Results.NoContent: Це вбудовані хелпери для повернення правильних HTTP статус-кодів (201 Created, 200 OK, 204 No Content).

Параметри маршрутів (Route Parameters)

Часто шлях містить динамічні значення. Наприклад, ми хочемо отримати користувача з ID 123 за адресою /users/123. Для цього ми використовуємо параметри маршрутів.

Параметри позначаються фігурними дужками {назва_параметра} всередині шаблону маршруту.

Просте зв'язування параметра

Program.cs
app.MapGet("/users/{id}", (int id) =>
{
    return $"ID користувача: {id}";
});

Анатомія коду:

  • Шаблон /users/{id} повідомляє роутеру, що після /users/ йде динамічна частина.
  • Значення цієї частини витягується зі шляху та автоматично конвертується в тип параметра нашої функції — int id.
  • Запит: GET /users/42 -> результат: "ID користувача: 42".
  • Що буде, якщо передати не число? Якщо ми зробимо запит GET /users/hello, фреймворк не зможе конвертувати "hello" в int і автоматично поверне помилку 400 Bad Request.

Декілька параметрів

Шлях може містити стільки параметрів, скільки потрібно, а як роздільник зазвичай використовують символ / (хоча можна й інші, наприклад -).

Program.cs
app.MapGet("/users/{userId}/books/{bookId}", (int userId, int bookId) =>
{
    return $"Користувач {userId} запитує книгу {bookId}";
});

Запит: GET /users/14/books/89 -> результат: "Користувач 14 запитує книгу 89".

Необов'язкові (Опціональні) параметри та дефолтні значення

Іноді параметр може бути відсутнім у URL. У такому випадку ми додаємо ? після імені параметра в шаблоні, а параметр у делегаті робимо nullable або задаємо дефолтне значення.

Program.cs
// Опціональний параметр
app.MapGet("/products/{category?}", (string? category) =>
{
    return $"Категорія: {category ?? "Усі товари"}";
});

// Параметр зі значенням за замовчуванням
app.MapGet("/articles/{page=1}", (int page) =>
{
    return $"Сторінка номер: {page}";
});

Анатомія коду:

  1. /products/{category?}: Запит /products/electronics поверне "Категорія: electronics". Запит /products — поверне "Категорія: Усі товари". Зверніть увагу на Nullable тип string?.
  2. /articles/{page=1}: Запит /articles встановить параметр page у значення 1.

Важливо: Опціональні параметри та параметри зі значеннями за замовчуванням мають бути останніми сегментами шаблону URL.

Як подивитися всі доступні маршрути?

Іноді під час розробки корисно побачити повний список зареєстрованих маршрутів. ASP.NET Core зберігає цю інформацію і дозволяє отримати до неї доступ через залежність IEnumerable<EndpointDataSource>.

Program.cs
app.MapGet("/debug/routes", (IEnumerable<EndpointDataSource> endpointSources) =>
{
    var endpoints = endpointSources.SelectMany(source => source.Endpoints);
    var routes = new List<string>();

    foreach (var endpoint in endpoints)
    {
        if (endpoint is RouteEndpoint routeEndpoint)
        {
            routes.Add(routeEndpoint.RoutePattern.RawText);
        }
    }

    return routes;
});

Анатомія коду:

  • Ми інжектуємо (додаємо як параметр) IEnumerable<EndpointDataSource>. Це внутрішня колекція фреймворку, яка тримає інформацію про всі роути.
  • Проходимось по всіх endpoint-ах і, якщо це RouteEndpoint, дістаємо його "сирий текст" (RoutePattern.RawText).
  • Повертаємо список як JSON масив string[].

Практичні завдання

Створення калькулятора (Додавання) Створіть Minimal API додаток з однією кінцевою точкою GET /add/{a}/{b}. Вона повинна приймати два цілих числа як параметри маршруту і повертати їх суму у вигляді рядка "Сума: X". Перевірте, як відреагує API, якщо замість числа передати текст.
Copyright © 2026