Filtering Collection Resources
What Is Filtering?
Section titled “What Is Filtering?”- Common Use Cases: For example, if you have an API that returns a list of species, you might want to filter this list based on parameters such as habitat, family, conservation status, or region.
Why Filtering Is Important?
Section titled “Why Filtering Is Important?”How to Implement Filtering in RESTful Web Services?
Section titled “How to Implement Filtering in RESTful Web Services?”1. Define filter criteria:
Section titled “1. Define filter criteria:”- Resource Identification: Determine which resource the filtering applies to. For example, if you have a
speciesresource, the endpoint might be/species. - Filtering Parameters: Decide on the parameters that clients can use to filter the data. These parameters could include various fields of the resource such as IDs, dates, names, or any other attributes relevant to your application.
Common Filter Types:
- Exact Match:
status=active,category=electronics - Range Queries:
price_min=10&price_max=100,date_after=2023-01-01 - Pattern Matching:
name_contains=smartphone,email_ends_with=@company.com - List Membership:
category_in=electronics,books,clothing
2. Design the API Endpoint:
Section titled “2. Design the API Endpoint:”Modify your API endpoints to accept filter parameters. Typically, filtering parameters are passed as query parameters in the URI of the GET request.
Example URI for filtering:
GET /api/species?habitat=forest&family=Felidae&conservation_status=endangeredIn this example:
habitatfilters species by their natural habitat.familyfilters species by their taxonomic family.conservation_statusfilters species by their conservation status.
3. Implement Filtering Logic on the Server Side:
Section titled “3. Implement Filtering Logic on the Server Side:”- Extract Parameters: Parse the query parameters from the request.
- Validate Parameters: Ensure that the parameters are valid and sanitize them to prevent issues such as SQL injection or other security vulnerabilities.
- Apply Filtering: Use the parameters to filter the data. This usually involves:
- Querying the database with filtering conditions.
- Iterating over a collection of objects and applying filter logic programmatically.
For example, in SQL, you might use:
SELECT * FROM species WHERE habitat = 'forest' AND family = 'Felidae' AND conservation_status = 'endangered';- Querying the database with filtering conditions.
- Or, iterating over a collection of objects and applying filter logic programmatically.
For example, in SQL, you might use:
SELECT * FROM species WHERE habitat = 'forest' AND family = 'Felidae' AND conservation_status = 'endangered';- Return the filtered data: Respond with the filtered data in the appropriate format (e.g., JSON or XML). Ensure that the response contains only the data that matches the criteria specified.
Filter Value Types
Section titled “Filter Value Types”When designing filter parameters, it’s important to understand the different data types that can be used:
| Value Type | Description | Example Query Parameters |
|---|---|---|
string | Text values for exact or partial matching | ?country=Japan, ?body_type=Mirrorless |
integer | Whole numbers | ?year=2020, ?generation=5 |
decimal | Numbers with decimal places | ?price=1999.99, ?aperture=1.4 |
boolean | True/false values | ?has_ibis=true, ?weather_sealed=false |
date | Date values (typically YYYY-MM-DD format) | ?release_date=2023-01-15 |
Range Filters
Section titled “Range Filters”Range filters allow clients to filter data within a specific range of values. A common convention is to use _min and _max suffixes on parameter names.
Single-Sided Range
Section titled “Single-Sided Range”Filter with only a lower or upper bound:
GET /api/cameras?price_min=1000Returns cameras costing at least $1000.
GET /api/cameras?weight_max=500Returns cameras weighing at most 500 grams.
Paired Range (Both Bounds)
Section titled “Paired Range (Both Bounds)”Filter within a specific range by providing both bounds:
GET /api/cameras?price_min=1000&price_max=3000Returns cameras costing between $1000 and $3000.
SQL Pattern for Range Filters
Section titled “SQL Pattern for Range Filters”SELECT * FROM camerasWHERE price >= :price_min AND price <= :price_maxDate Filters
Section titled “Date Filters”Date filters use _after and _before suffixes to filter records based on date fields.
Examples
Section titled “Examples”GET /api/cameras?release_date_after=2020-01-01Returns cameras released after January 1, 2020.
GET /api/cameras?release_date_before=2023-12-31Returns cameras released before December 31, 2023.
GET /api/cameras?release_date_after=2020-01-01&release_date_before=2023-12-31Returns cameras released between 2020 and 2023.
SQL Patterns for Date Filters
Section titled “SQL Patterns for Date Filters”After only:
SELECT * FROM camerasWHERE release_date > :date_afterBefore only:
SELECT * FROM camerasWHERE release_date < :date_beforeBetween (both bounds):
SELECT * FROM camerasWHERE release_date > :date_after AND release_date < :date_beforeAggregation Filters (Count-Based)
Section titled “Aggregation Filters (Count-Based)”Some filters require filtering based on aggregated data — for example, finding manufacturers that produce a minimum number of camera models. These require GROUP BY and HAVING clauses in SQL.
Example Use Case
Section titled “Example Use Case”Find manufacturers who produce at least 10 camera models:
GET /api/manufacturers?camera_count_min=10SQL Pattern for Aggregation Filters
Section titled “SQL Pattern for Aggregation Filters”SELECT m.*, COUNT(cb.body_id) AS camera_countFROM manufacturers mLEFT JOIN camera_bodies cb ON m.manufacturer_id = cb.manufacturer_idGROUP BY m.manufacturer_idHAVING COUNT(cb.body_id) >= :min_countCombining Multiple Filters
Section titled “Combining Multiple Filters”Multiple filters can be combined in a single request using & to separate parameters:
GET /api/cameras?price_min=1500&body_type=Mirrorless&has_ibis=trueThis returns:
- Mirrorless cameras
- With image stabilization (IBIS)
- Costing at least $1500
Case-Insensitive Filtering
Section titled “Case-Insensitive Filtering”When filtering by string values, users might search using different cases:
?manufacturer=canon?manufacturer=Canon?manufacturer=CANON
All three should return the same results. Here’s how to implement case-insensitive filtering.
Using LOWER() Function
Section titled “Using LOWER() Function”The most portable approach is to convert both the column and search term to lowercase:
SELECT * FROM manufacturersWHERE LOWER(name) = LOWER(:search_term)Using COLLATE (MySQL)
Section titled “Using COLLATE (MySQL)”A more performant MySQL-specific approach is to use a case-insensitive collation:
SELECT * FROM manufacturersWHERE name COLLATE utf8mb4_general_ci = :search_termThe utf8mb4_general_ci collation performs case-insensitive (ci) comparisons.
Using LIKE for Partial Matching
Section titled “Using LIKE for Partial Matching”For partial, case-insensitive matching:
SELECT * FROM manufacturersWHERE LOWER(name) LIKE LOWER(:search_pattern)