In the last post, we tackled Pagination breaking down large API responses into manageable chunks. But if you've ever wanted to let users control how data is sorted or filter specific results, then you're ready for the next step: sorting and filtering.
Let's dive in and make our APIs even more powerful by adding these features.
If you haven't gone through the previous tutorial, here's the link.
Pagination alone isn't always enough. Imagine a user searching for the newest items or only those created in a specific timeframe. Sorting and filtering let users:
- Sort: Choose the order of results (e.g. newest to oldest)
- Filter: Narrow down results to what they need (e.g. items created today)
By combining pagination with sorting and filtering, we create a more user-friendly API.
We'll build on the items table from the previous blog. To recap, here's the scheme:
CREATE TABLE items ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, created_at TIMESTAMP DEFAULT NOW() );
Sorting is all about ordering the results. We'll allow users to sort by the name or created_at columns in ascending or descending order.
Users will pass two query parameters:
Example URL:
/items?page=1&limit=10&sort=created_at&order=desc
We'll dynamically modify the SQL query to include sorting:
// Extract sort and order query parameters sort := r.URL.Query().Get("sort") order := r.URL.Query().Get("order") // Validate the sort column validSortColumns := map[string]bool{"name": true, "created_at": true} if !validSortColumns[sort] { sort = "created_at" // Default sort column } // Validate the sort order if order != "asc" && order != "desc" { order = "asc" // Default sort order } // Modify the SQL query query := fmt.Sprintf("SELECT id, name, created_at FROM items ORDER BY %s %s LIMIT OFFSET ", sort, order) rows, err := db.Query(query, limit, offset) if err != nil { http.Error(w, "Failed to fetch items", http.StatusInternalServerError) return }
Filtering lets users refine their search. For example, we can filter items by a date range or items containing a specific keyword in their name.
We'll support two filters:
Example URL :
/items?page=1&limit=10&name=Item&created_after=2025-01-10 20:38:57.832777
We'll add WHERE conditions to handle these filters:
CREATE TABLE items ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, created_at TIMESTAMP DEFAULT NOW() );
/items?page=1&limit=10&sort=created_at&order=desc
// Extract sort and order query parameters sort := r.URL.Query().Get("sort") order := r.URL.Query().Get("order") // Validate the sort column validSortColumns := map[string]bool{"name": true, "created_at": true} if !validSortColumns[sort] { sort = "created_at" // Default sort column } // Validate the sort order if order != "asc" && order != "desc" { order = "asc" // Default sort order } // Modify the SQL query query := fmt.Sprintf("SELECT id, name, created_at FROM items ORDER BY %s %s LIMIT OFFSET ", sort, order) rows, err := db.Query(query, limit, offset) if err != nil { http.Error(w, "Failed to fetch items", http.StatusInternalServerError) return }
/items?page=1&limit=10&name=Item&created_after=2025-01-10 20:38:57.832777
Not validating user input: Allowing arbitrary columns or invalid sort orders can expose your database to SQL injection. Always validate inputs.
You can find the complete code repository for this tutorial here
With pagination, sorting, and filtering in place, your API is now more user-friendly and flexible. For even more advanced functionality, consider adding:
Stay tuned for the next post where we’ll explore these advanced techniques!
To get more information about Golang concepts, projects, etc. and to stay updated on the Tutorials do follow Siddhesh on Twitter and GitHub.
Until then Keep Learning, Keep Building ??
The above is the detailed content of Taking Pagination to the Next Level: Sorting and Filtering in Go APIs. For more information, please follow other related articles on the PHP Chinese website!