Validation
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
Client gửi sản phẩm tên rỗng, giá âm. Nếu API cứ thế lưu vào thì dữ liệu hỏng từ đầu. Validation chặn dữ liệu sai ngay ở cửa, trước khi action kịp chạy.
Khái niệm
✅ Validation: bước kiểm tra dữ liệu client gửi lên có hợp lệ không trước khi xử lý.
🔖 Data annotation: attribute gắn lên property của DTO để khai báo quy tắc, ví dụ [Required], [Range].
| Attribute | Quy tắc |
|---|---|
[Required] |
bắt buộc có, chuỗi không được rỗng |
[StringLength(100)] |
chuỗi tối đa 100 ký tự |
[Range(1, 100000000)] |
số nằm trong khoảng |
[EmailAddress] |
đúng định dạng email |
Ví dụ
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
[HttpPost]
public ActionResult<string> Create(
CreateProductRequest request)
{
return Ok($"Đã tạo {request.Name}");
}
}
public class CreateProductRequest
{
[Required(ErrorMessage = "Tên không được trống")]
[StringLength(100)]
public string Name { get; set; } = "";
[Range(1, 100000000,
ErrorMessage = "Giá phải từ 1 đến 100 triệu")]
public decimal Price { get; set; }
}- Quy tắc nằm ngay trên DTO, cần
using System.ComponentModel.DataAnnotations. [ApiController]tự kiểm tra DTO trước khi gọi action. Sai quy tắc thì trả 400 kèm danh sách lỗi, action không chạy.ErrorMessageđặt câu báo lỗi riêng thay cho câu mặc định bằng tiếng Anh.- Validation chặn ở API để trả 400 dễ hiểu.
NOT NULL,CHECKở bài CREATE TABLE của khoá SQL vẫn là lớp chặn cuối trong database.
Thử ngay
Chạy server. Tạo file product.json với dữ liệu sai:
{ "name": "", "price": -5 }Rồi gửi:
curl -i -X POST http://localhost:5000/api/products -H "Content-Type: application/json" -d @product.jsonĐoán trước khi chạy: action có chạy tới dòng return Ok(...) không, và
response báo mấy lỗi?
Xem kết quả
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Name": ["T\u00EAn kh\u00F4ng \u0111\u01B0\u1EE3c tr\u1ED1ng"],
"Price": ["Gi\u00E1 ph\u1EA3i t\u1EEB 1 \u0111\u1EBFn 100 tri\u1EC7u"]
}
}Body trên đã rút gọn, bản thật có thêm type và traceId.
Action không chạy. [ApiController] chặn từ trước và trả 400 kèm hai lỗi,
mỗi lỗi gắn với tên property. Chữ có dấu bị mã hoá dạng \u00EA khi xem
bằng curl, còn client đọc JSON sẽ hiện lại đúng "Tên không được trống".
Lỗi hay gặp
Tự kiểm tra bằng if trong từng action. Quy tắc bị chép rải rác, sửa một
chỗ dễ quên chỗ khác.
// SAI — quy tắc nằm trong action, phải chép lại ở PUT
using Microsoft.AspNetCore.Mvc;
public class ItemsController : ControllerBase
{
[HttpPost]
public ActionResult<string> Create(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return BadRequest("Tên không được trống");
}
return Ok(name);
}
}Đặt quy tắc thành attribute trên DTO thì mọi action dùng DTO đó đều được kiểm tra.
// ĐÚNG — quy tắc nằm trên DTO
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/items")]
public class ItemsController : ControllerBase
{
[HttpPost]
public ActionResult<string> Create(
CreateItemRequest request)
{
return Ok(request.Name);
}
}
public class CreateItemRequest
{
[Required(ErrorMessage = "Tên không được trống")]
public string Name { get; set; } = "";
}Quên [ApiController]. Không có nó thì dữ liệu sai vẫn lọt vào action,
vì không còn bước nào tự trả 400.
Tóm tắt
- Validation chặn dữ liệu sai trước khi action chạy.
- Khai báo quy tắc bằng attribute trên DTO:
[Required],[Range],[StringLength]. [ApiController]tự trả 400 kèm danh sách lỗi theo từng property.- Dùng
ErrorMessageđể có câu báo lỗi dễ hiểu cho người dùng.
Tự kiểm tra
0/3 câuDTO có [Range(1, 10)] public int Quantity. Client gửi quantity = 0. Chuyện gì xảy ra?
Muốn email của khách hàng vừa bắt buộc vừa đúng định dạng. Gắn attribute nào?
Quy tắc validation nên đặt ở đâu?