Contents

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.

https://blog-bucket.luandnh.com/images/covers/api-filtering.webp

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=50000

Mộ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=desc

Sorting 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,price

Chỉ đị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=20

Backend 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é! ☕