Trả về kết quả
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
Ở bài Controller và routing, gọi API lấy sản phẩm không tồn tại thì nhận về 204 thay vì 404. Client không phân biệt được "không có" với "thành công". Bài này chỉ cách chọn đúng status code cho từng trường hợp.
Khái niệm
📬 ActionResultT, hoặc một kết quả kèm status code như 404.
Các method có sẵn trong ControllerBase để tạo kết quả:
| Method | Status code | Khi nào dùng |
|---|---|---|
Ok(data) |
200 | đọc thành công, có dữ liệu |
CreatedAtAction(...) |
201 | tạo mới thành công |
NoContent() |
204 | thành công, không có gì trả về |
BadRequest() |
400 | dữ liệu gửi lên sai |
NotFound() |
404 | không tìm thấy |
Ví dụ
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
private static readonly List<Product> Products =
new List<Product>();
[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
var product =
Products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
[HttpPost]
public ActionResult<Product> Create(Product product)
{
product.Id = Products.Count + 1;
Products.Add(product);
return CreatedAtAction(
nameof(GetById),
new { id = product.Id },
product);
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}ActionResult<Product>cho phép trảNotFound()ở nhánh này vàOk(product)ở nhánh kia.CreatedAtActiontrả 201, kèm headerLocationchỉ tới URL của sản phẩm vừa tạo, ví dụ/api/products/1.nameof(GetById)chỉ ra action dùng để dựng URL đó. Viết bằngnameofthì khi đổi tên method, compiler báo lỗi ngay.new { id = product.Id }tạo nhanh một object không cần khai báo class, dùng để điền{id}vào URL.
Thử ngay
Chạy server. Tạo file product.json có nội dung { "name": "Pen", "price": 5000 },
rồi gọi:
curl -i -X POST http://localhost:5000/api/products -H "Content-Type: application/json" -d @product.json
curl -i http://localhost:5000/api/products/1
curl -i http://localhost:5000/api/products/99Đoán trước khi chạy: lần gọi POST trả về status code nào, và lần gọi cuối còn là 204 không?
Xem kết quả
HTTP/1.1 201 Created
Location: http://localhost:5000/api/products/1
{"id":1,"name":"Pen","price":5000}
HTTP/1.1 200 OK
{"id":1,"name":"Pen","price":5000}
HTTP/1.1 404 Not FoundPOST trả 201 kèm Location. Sản phẩm 99 giờ trả 404, vì action chủ động gọi
NotFound() thay vì trả null.
Lỗi hay gặp
Trả null khi không tìm thấy. Client nhận 204, tưởng là thành công.
// SAI — không tìm thấy mà vẫn là "thành công"
using Microsoft.AspNetCore.Mvc;
public class OrdersController : ControllerBase
{
[HttpGet("{id}")]
public string? GetById(int id)
{
return null;
}
}// ĐÚNG
using Microsoft.AspNetCore.Mvc;
public class OrdersController : ControllerBase
{
[HttpGet("{id}")]
public ActionResult<string> GetById(int id)
{
return NotFound();
}
}Tạo mới mà trả 200. Tạo thành công nên trả 201 qua CreatedAtAction,
để client biết ngay URL của thứ vừa tạo.
Tóm tắt
- Dùng
ActionResult<T>để một action trả được cả dữ liệu lẫn lỗi. - Đọc được thì
Ok, tạo mới thìCreatedAtAction, không có thìNotFound. - Không trả
nullkhi không tìm thấy, vì client sẽ nhận 204. - Status code đúng giúp client xử lý mà không phải đọc body.
Tự kiểm tra
0/3 câuAction xoá sản phẩm thành công và không cần trả dữ liệu gì. Nên trả gì?
Action trả ActionResult<Order>. Không tìm thấy đơn hàng thì viết gì?
Sau khi tạo khách hàng mới, response có header Location. Header này dùng để làm gì?