Ответ
RESTful-контроллер в ASP.NET Core — это контроллер, который следует принципам архитектуры REST (Representational State Transfer). Его ключевые характеристики:
- Использует HTTP-методы для операций CRUD:
GET— получение ресурса или коллекции.POST— создание нового ресурса.PUT— полное обновление ресурса.PATCH— частичное обновление ресурса.DELETE— удаление ресурса.
- Использует маршрутизацию на основе ресурсов (RESTful-маршруты). Имена методов контроллера часто соответствуют шаблонам действий (например,
Get(),Post([FromBody] Model model)), но основную роль играют атрибуты HTTP-методов. - Возвращает соответствующие коды состояния HTTP (200 OK, 201 Created, 404 Not Found и т.д.).
- Работает с представлениями данных (DTO/ViewModel), а не напрямую с доменными моделями.
- Является stateless — каждому запросу передается вся необходимая информация.
Пример RESTful-контроллера для сущности Product:
[ApiController]
[Route("api/[controller]")] // Маршрут: /api/products
public class ProductsController : ControllerBase
{
private readonly IProductService _service;
public ProductsController(IProductService service)
{
_service = service;
}
// GET: api/products
[HttpGet]
public async Task<ActionResult<IEnumerable<ProductDto>>> GetProducts()
{
var products = await _service.GetAllAsync();
return Ok(products); // 200 OK
}
// GET: api/products/5
[HttpGet("{id}")]
public async Task<ActionResult<ProductDto>> GetProduct(int id)
{
var product = await _service.GetByIdAsync(id);
if (product == null)
{
return NotFound(); // 404 Not Found
}
return Ok(product); // 200 OK
}
// POST: api/products
[HttpPost]
public async Task<ActionResult<ProductDto>> PostProduct(ProductCreateDto createDto)
{
var createdProduct = await _service.CreateAsync(createDto);
// Возвращаем созданный ресурс и его местоположение
return CreatedAtAction(nameof(GetProduct),
new { id = createdProduct.Id },
createdProduct); // 201 Created
}
// PUT: api/products/5
[HttpPut("{id}")]
public async Task<IActionResult> PutProduct(int id, ProductUpdateDto updateDto)
{
if (id != updateDto.Id)
{
return BadRequest(); // 400 Bad Request
}
await _service.UpdateAsync(updateDto);
return NoContent(); // 204 No Content
}
// DELETE: api/products/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
await _service.DeleteAsync(id);
return NoContent(); // 204 No Content
}
}
Использование атрибута [ApiController] автоматически включает такие функции, как проверка модели (возврат 400 при невалидных данных) и привязка параметров из тела запроса.
Ответ 18+ 🔞
А, ну это ж про эти ваши RESTful-контроллеры в ASP.NET Core! Представь, что у тебя есть какой-нибудь ресурс, ну, продукты там. Так вот, это такой контроллер, который не городит огород, а работает по понятным правилам, как дорожные знаки. Всё через HTTP-методы, всё прозрачно, ебать колотить!
Смотри, суть в чём: каждый метод в этом контроллере — это как отдельная команда, и команда эта определяется не хитрым названием функции, а тем, КАК ты к нему обращаешься. GET — пришёл, взял данные. POST — принёс, создал новое. PUT — принёс, полностью заменил старую запись. DELETE — пришёл, нахуй удалил. PATCH — это когда ты не хочешь менять всё, а только кусочек подправить, хитрая жопа.
И маршруты у них красивые, человеческие. Не api/Products/GetAllProducts, а просто GET api/products. Не api/Products/DeleteProductById?id=5, а DELETE api/products/5. Элегантно, блядь! Статусы они тоже возвращают правильные: нашёл запись — 200 OK, не нашёл — 404 Not Found, создал — 201 Created, хуйнул — 204 No Content. Всё как у взрослых.
Вот смотри на пример, тут всё разложено по полочкам:
[ApiController]
[Route("api/[controller]")] // Теперь все запросы к /api/products идут сюда
public class ProductsController : ControllerBase
{
private readonly IProductService _service; // Зависимость, логику выносим в сервис
public ProductsController(IProductService service)
{
_service = service;
}
// GET: api/products
[HttpGet]
public async Task<ActionResult<IEnumerable<ProductDto>>> GetProducts()
{
var products = await _service.GetAllAsync();
return Ok(products); // 200 OK и список продуктов
}
// GET: api/products/5
[HttpGet("{id}")]
public async Task<ActionResult<ProductDto>> GetProduct(int id)
{
var product = await _service.GetByIdAsync(id);
if (product == null)
{
return NotFound(); // 404 — нихуя не нашли по такому айди
}
return Ok(product); // 200 — вот, держи, что просил
}
// POST: api/products
[HttpPost]
public async Task<ActionResult<ProductDto>> PostProduct(ProductCreateDto createDto)
{
var createdProduct = await _service.CreateAsync(createDto);
// Возвращаем 201 Created, ссылку на новую хуйню и её саму в теле
return CreatedAtAction(nameof(GetProduct),
new { id = createdProduct.Id },
createdProduct);
}
// PUT: api/products/5
[HttpPut("{id}")]
public async Task<IActionResult> PutProduct(int id, ProductUpdateDto updateDto)
{
if (id != updateDto.Id) // Айди в пути и в теле не совпали? Пизда рулю.
{
return BadRequest(); // 400 Bad Request
}
await _service.UpdateAsync(updateDto);
return NoContent(); // 204 No Content — всё обновил, тебе больше ничего не шлю
}
// DELETE: api/products/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
await _service.DeleteAsync(id);
return NoContent(); // 204 — удалил, иди нахуй
}
}
И главный прикол — атрибут [ApiController] сверху. Это такая волшебная палочка, которая автоматом включает кучу плюшек: если данные в запросе кривые — вернёт 400, не надо самому проверять; параметры из тела запроса сам подтянет. В общем, жизнь облегчает, терпения ебать ноль тратить на рутину. Красота, а не архитектура!