API Filtering: gọi dữ liệu như dân sành cà phê
Mở đầu
Bạn bước vào quán cà phê, menu dài cả trang. Bạn không muốn “nào cũng được”, bạn muốn đúng gu: iced Americano, ít đường, hạt Ethiopia. Barista ghi order, pha chế, bạn nhận ly cà phê đúng ý — không thừa, không thiếu.
Khi làm việc với API cũng vậy: ta không lấy cả “menu” dữ liệu, ta chỉ lấy đúng phần mình cần. Bài viết này giải thích cách “đặt món” dữ liệu hiệu quả với Filtering, Sorting và Selecting fields — những kỹ thuật giúp API nhẹ hơn, nhanh hơn, và dễ dùng hơn.

Chỉ món đang bán chạy — Lọc cơ bản
Hãy giả sử menu có hàng trăm món nhưng bạn chỉ muốn thứ đang còn hàng (status=active). Trong API, bạn sẽ lọc như sau:
GET /api/data?status=activeĐơn giản, nhưng bước này không phải lúc nào cũng rõ ràng khi bạn thiết kế API. Câu hỏi lớn là: “Client muốn lọc theo gì, và backend hỗ trợ lọc như thế nào?”
Khi order chi tiết hơn — Toán tử lọc
Ví dụ: “chỉ lấy sản phẩm có giá từ 50k trở lên”. Trong API, dùng toán tử so sánh:
GET /api/products?price_gte=50000Một số toán tử phổ biến:
| Toán tử | Ý nghĩa | Ví dụ |
|---|---|---|
_eq |
Bằng | status=active |
_ne |
Khác | category_ne=archived |
_gt / _gte |
Lớn hơn / lớn hơn hoặc bằng | price_gte=50000 |
_lt / _lte |
Nhỏ hơn / nhỏ hơn hoặc bằng | created_at_lte=2025-08-01 |
_in |
Trong danh sách | status_in=active,pending |
_like |
Tìm kiếm mờ | name_like=coffee |
// Backend: parse query params thành filters
func parseFilters(url.Values) ([]Filter, error) {
var filters []Filter
for key, values := range q {
// price_gte=50000 → {field: "price", op: "gte", value: 50000}
if strings.HasSuffix(key, "_gte") {
field := strings.TrimSuffix(key, "_gte")
filters = append(filters, Filter{field, ">=", parseFloat(values[0])})
}
// ... các toán tử khác
}
return filters, nil
}Xếp món mới nhất lên đầu — Sắp xếp dữ liệu
GET /api/posts?sort=created_at&order=descSorting giúp client kiểm soát thứ tự dữ liệu mà không cần xử lý ở frontend. Backend nên index cột sort phổ biến để tránh full table scan:
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);Đừng làm sorting quá linh hoạt (?sort=field1,-field2,field3...) mà không có validation — bạn sẽ bị SQL injection hoặc performance nếu client sort theo cột không có index.
Tôi chỉ cần tên và giá — Chọn trường trả về
GET /api/products?fields=name,priceChỉ định trường (field selection) giúp giảm payload đáng kể khi bảng có nhiều cột. Một response JSON “gầy” 20 trường có thể giảm xuống còn 2-3 trường cần thiết.
// Chỉ SELECT các trường client yêu cau
fields := req.URL.Query().Get("fields")
if fields != "" {
columns := strings.Split(fields, ",")
db = db.Select(columns)
}Pagination kết hợp
Khi kết hợp filtering + sorting + pagination:
GET /api/products?category=tea&price_gte=30000&sort=price&order=asc&page=1&limit=20Backend nên handle theo thứ tự: Filter → Sort → Paginate. Đừng paginate trước rồi mới filter — bạn sẽ bị thiếu dữ liệu.
Lời kết từ quán cà phê
Giao tiếp với API là một cuộc đối thoại tinh gọn. Bạn hỏi càng rõ, phản hồi càng chính xác và nhẹ nhàng. Filtering, sorting, và selecting fields không phải tính năng “nice-to-have” — chúng là nền tảng của một API thiết kế tốt.
“Đặt món rõ ràng, phục vụ nhanh nhất.”
Thắc mắc về API design? Comment bên dưới, mình cùng thảo luận nhé! ☕