4. REST API событий¶
Цель¶
Создать контроллер EventsController и проверить CRUD-операции через Swagger или HTTP-клиент.
Объяснение¶
Контроллер не должен знать, как устроен EF Core. Он получает запрос, вызывает сервис и возвращает статус HTTP.
На этом этапе вы впервые увидите приложение “снаружи”. До этого были модели, контекст базы данных, репозиторий и сервис. Они важны, но пользователь или внешний клиент не обращается к ним напрямую. REST API делает вашу бизнес-логику доступной через HTTP.
Представьте путь запроса POST /api/events:
- Клиент отправляет JSON с описанием события.
EventsControllerпринимает этот JSON.- Контроллер определяет текущего пользователя. Пока авторизации нет, временно используется
Id = 1. - Контроллер вызывает
CreateAsync. - Сервис создаёт событие и передаёт его в репозиторий.
- Репозиторий сохраняет запись в SQLite.
- API возвращает созданное событие и статус
201 Created.
Именно поэтому важно не пропускать предыдущие этапы: контроллер в этом разделе опирается на уже созданные DTO, интерфейсы, сервисы и регистрацию зависимостей.
Код¶
Теперь добавляется HTTP-точка входа в уже готовую бизнес-логику. EventsController принимает параметры из запроса, вызывает IActivityEventService и преобразует результат работы сервиса в стандартные HTTP-ответы.
ActivityMonitoring.Api/Controllers/EventsController.cs:
using System.Security.Claims;
using ActivityMonitoring.Application.Events;
using Microsoft.AspNetCore.Mvc;
namespace ActivityMonitoring.Api.Controllers;
[ApiController]
[Route("api/events")]
public class EventsController : ControllerBase
{
private readonly IActivityEventService _service;
public EventsController(IActivityEventService service)
{
_service = service;
}
[HttpGet]
public async Task<ActionResult<IReadOnlyList<ActivityEventDto>>> Get(
[FromQuery] ActivityEventFilter filter,
CancellationToken ct)
{
var result = await _service.GetAsync(filter, ct);
return Ok(result);
}
[HttpPost]
public async Task<ActionResult<ActivityEventDto>> Create(
CreateActivityEventRequest request,
CancellationToken ct)
{
var userId = GetCurrentUserIdOrDefault();
var result = await _service.CreateAsync(request, userId, ct);
return Created($"/api/events/{result.Id}", result);
}
[HttpDelete("{id:int}")]
public async Task<IActionResult> Delete(int id, CancellationToken ct)
{
var deleted = await _service.DeleteAsync(id, ct);
return deleted ? NoContent() : NotFound();
}
private int GetCurrentUserIdOrDefault()
{
var claim = User.FindFirstValue(ClaimTypes.NameIdentifier);
return int.TryParse(claim, out var userId) ? userId : 1;
}
}
На этом этапе авторизация ещё не включена, поэтому временно используется пользователь admin с Id = 1.
Такой временный код нужен только для учебного перехода. В следующем этапе метод GetCurrentUserIdOrDefault начнёт брать пользователя из JWT-токена. В реальной системе нельзя автоматически подставлять администратора, потому что это нарушает безопасность.
Куда вставлять код¶
Создайте файл именно в проекте API:
Если контроллер случайно создать в Application или Infrastructure, ASP.NET Core не найдёт его как HTTP-контроллер.
После добавления файла проверьте, что в Program.cs есть строки:
Первая строка подключает механизм контроллеров, вторая добавляет маршруты контроллеров в приложение.
После этого запустите API. Запуск нужен не только для проверки компиляции: ASP.NET Core при старте также проверит регистрацию зависимостей, маршруты контроллеров и подключение конфигурации.
Первым HTTP-запросом создайте событие. Он проверяет полный путь от контроллера до базы данных: JSON попадает в DTO, сервис создаёт ActivityEvent, репозиторий сохраняет запись, а API возвращает созданный объект.
POST http://localhost:5000/api/events
Content-Type: application/json
{
"type": "PageView",
"source": "swagger",
"description": "Открыта страница аналитики",
"severity": "Info"
}
Затем запросите список событий. Этот запрос нужен, чтобы убедиться, что созданная запись действительно сохранена и что фильтр с пагинацией корректно передаётся из query string в сервис.
Как понять, что всё работает¶
Проверка считается успешной, если выполняются три условия:
POST /api/eventsвозвращает статус201 Created.- В ответе есть поле
id, которое больше нуля. GET /api/eventsвозвращает созданное событие в списке.
Если POST сработал, но GET возвращает пустой список, проверьте, что приложение использует ту же базу данных, в которую была применена миграция.
Частые проблемы¶
| Проблема | Возможная причина | Решение |
|---|---|---|
| Swagger не показывает контроллер | Нет app.MapControllers() |
Добавить строку в Program.cs |
| Ошибка DI при запуске | Не зарегистрирован сервис или репозиторий | Проверить AddScoped<IActivityEventService, ActivityEventService>() |
Ошибка no such table |
Не выполнена миграция | Выполнить dotnet ef database update |
В ответе User равен null |
Не загружена навигация User |
Проверить Include(x => x.User) или LoadAsync в репозитории |
Результат¶
API умеет создавать, получать и удалять события активности. На следующем этапе эти эндпоинты будут защищены JWT-токеном.
После завершения этапа у проекта появляется первый полноценный пользовательский сценарий: внешняя система может отправить событие активности, а аналитик или администратор может получить список таких событий.