Easy📖Теория2 min

Шаг 17: OrdersController

Создание REST API контроллера с MediatR: CRUD endpoints для заказов, атрибуты маршрутизации, ProducesResponseType и CancellationToken

Шаг 17: OrdersController

Controller принимает HTTP-запросы и делегирует обработку через MediatR. Контроллер максимально тонкий -- три действия: принять запрос, создать Command/Query, вернуть результат.

OrdersController.cs

В папке Controllers проекта API:

using MediatR;
using Microsoft.AspNetCore.Mvc;
using OrderManagement.Application.Orders.Commands.CancelOrder;
using OrderManagement.Application.Orders.Commands.ConfirmOrder;
using OrderManagement.Application.Orders.Commands.CreateOrder;
using OrderManagement.Application.Orders.DTOs;
using OrderManagement.Application.Orders.Queries.GetCustomerOrders;
using OrderManagement.Application.Orders.Queries.GetOrder;

namespace OrderManagement.API.Controllers;

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IMediator _mediator;

    public OrdersController(IMediator mediator) =>
        _mediator = mediator;

    [HttpPost]
    [ProducesResponseType(typeof(Guid), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> Create(
        [FromBody] CreateOrderCommand command,
        CancellationToken ct)
    {
        var orderId = await _mediator.Send(command, ct);
        return CreatedAtAction(
            nameof(GetById), new { id = orderId }, orderId);
    }

    [HttpGet("{id:guid}")]
    [ProducesResponseType(typeof(OrderDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetById(
        Guid id, CancellationToken ct)
    {
        var order = await _mediator.Send(
            new GetOrderQuery(id), ct);
        return Ok(order);
    }

    [HttpGet("customer/{customerId}")]
    [ProducesResponseType(typeof(List<OrderDto>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetByCustomer(
        string customerId, CancellationToken ct)
    {
        var orders = await _mediator.Send(
            new GetCustomerOrdersQuery(customerId), ct);
        return Ok(orders);
    }

    [HttpPost("{id:guid}/confirm")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> Confirm(
        Guid id, CancellationToken ct)
    {
        await _mediator.Send(new ConfirmOrderCommand(id), ct);
        return NoContent();
    }

    [HttpPost("{id:guid}/cancel")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> Cancel(
        Guid id, [FromBody] CancelRequest request,
        CancellationToken ct)
    {
        await _mediator.Send(
            new CancelOrderCommand(id, request.Reason), ct);
        return NoContent();
    }
}

public record CancelRequest(string Reason);

[ApiController] включает автоматическую валидацию ModelState. [Route("api/[controller]")] -- URL /api/orders. CreatedAtAction возвращает 201 с заголовком Location. CancellationToken передаётся ASP.NET Core автоматически.

Проверь себя

🧪

Что делает атрибут [ApiController]?

🧪

Зачем CancellationToken передаётся в методы контроллера?

🧪

Что возвращает CreatedAtAction?