Pagination & Filters
Advanced data querying for file-based endpoints returning JSON arrays.
Overview
Pagination and filtering work only with:
- ✅ File-based endpoints
- ✅ Files containing JSON arrays
- ✅ Methods: GET, POST, HEAD, DELETE
- ❌ Custom handlers (unless manually implemented)
- ❌ JSON objects (not arrays)
- ❌ Non-JSON files
Pagination
Configuration
typescript
import { defineConfig } from 'vite'
// import mockApi from '@ndriadev/vite-plugin-universal-api' //Default export
import { universalApi } from '@ndriadev/vite-plugin-universal-api' // Named export
export default defineConfig({
plugins: [
universalApi({
endpointPrefix: '/api',
fsDir: 'mock',
pagination: {
GET: {
type: 'query-param', // or 'body'
limit: 'limit', // Query param name
skip: 'skip', // Query param name
sort: 'sortBy', // Query param name
order: 'order' // Query param name
}
}
})
]
})Query Param Type
Send pagination parameters in URL query string:
bash
GET /api/users?limit=10&skip=20&sortBy=name&order=ascConfiguration:
typescript
pagination: {
GET: {
type: 'query-param',
limit: 'limit',
skip: 'skip',
sort: 'sortBy',
order: 'order'
}
}Body Type
Send pagination parameters in request body:
bash
POST /api/users
Content-Type: application/json
{
"pagination": {
"limit": 10,
"skip": 20,
"sortBy": "name",
"order": "asc"
}
}Configuration:
typescript
pagination: {
POST: {
type: 'body',
root: 'pagination', // Root key in body
limit: 'limit',
skip: 'skip',
sort: 'sortBy',
order: 'order'
}
}Pagination Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
limit | number | Max items to return | 10 |
skip | number | Items to skip | 20 |
sort | string | Field to sort by | name |
order | string | Sort order | asc or desc |
Response Format
The response includes pagination metadata in headers:
HTTP/1.1 200 OK
Content-Type: application/json
X-Total-Elements: 150
Content-Length: 1234
[
{"id": 21, "name": "User 21"},
{"id": 22, "name": "User 22"},
...
]Headers:
X-Total-Elements: Total count before paginationContent-Length: Response body size
Examples
Basic Pagination
bash
# Get first 10 users
GET /api/users?limit=10&skip=0
# Get next 10 users
GET /api/users?limit=10&skip=10
# Get users 21-30
GET /api/users?limit=10&skip=20With Sorting
bash
# Sort by name ascending
GET /api/users?limit=10&skip=0&sortBy=name&order=asc
# Sort by age descending
GET /api/users?limit=10&skip=0&sortBy=age&order=desc
# Sort by createdAt descending (most recent first)
GET /api/users?sortBy=createdAt&order=descDefault Values
If not provided, defaults apply:
limit: All items (no limit)skip: 0sort: No sorting (original order)order:asc
Filters
Configuration
typescript
filters: {
GET: {
type: 'query-param',
filters: [
{
key: 'status', // Query param name
field: 'status', // Field in data (optional, defaults to key)
valueType: 'string', // Data type
comparison: 'eq' // Comparison operator
},
{
key: 'minAge',
field: 'age',
valueType: 'number',
comparison: 'gte'
}
]
}
}Query Param Type
bash
GET /api/users?status=active&minAge=18Body Type
bash
POST /api/users
Content-Type: application/json
{
"filters": {
"status": "active",
"minAge": 18
}
}Configuration:
typescript
filters: {
POST: {
type: 'body',
root: 'filters', // Root key in body
filters: [...]
}
}Comparison Operators
| Operator | Description | Example |
|---|---|---|
eq | Equals | status=active → status == 'active' |
neq | Not equals | status=inactive → status != 'inactive' |
gt | Greater than | age=18 → age > 18 |
gte | Greater than or equal | age=18 → age >= 18 |
lt | Less than | age=65 → age < 65 |
lte | Less than or equal | age=65 → age <= 65 |
in | Value in array | id=1,2,3 → id in [1,2,3] |
nin | Value not in array | id=4,5 → id not in [4,5] |
contains | String contains (case-insensitive) | name=john → name includes 'john' |
Value Types
Specify data type for proper comparison:
typescript
valueType: 'string' // String comparison
valueType: 'number' // Numeric comparison
valueType: 'boolean' // Boolean comparisonFilter Examples
String Filters
typescript
filters: [
{
key: 'status',
valueType: 'string',
comparison: 'eq'
}
]bash
GET /api/users?status=active
# Returns users where status === 'active'Numeric Filters
typescript
filters: [
{
key: 'minAge',
field: 'age',
valueType: 'number',
comparison: 'gte'
},
{
key: 'maxAge',
field: 'age',
valueType: 'number',
comparison: 'lte'
}
]bash
GET /api/users?minAge=18&maxAge=65
# Returns users where age >= 18 AND age <= 65Array Filters
typescript
filters: [
{
key: 'ids',
field: 'id',
valueType: 'number',
comparison: 'in'
}
]bash
GET /api/users?ids=1,2,3,5,8
# Returns users where id in [1,2,3,5,8]Contains Filter
typescript
filters: [
{
key: 'search',
field: 'name',
valueType: 'string',
comparison: 'contains'
}
]bash
GET /api/users?search=john
# Returns users where name contains 'john' (case-insensitive)Combining Pagination & Filters
typescript
universalApi({
pagination: {
GET: {
type: 'query-param',
limit: 'limit',
skip: 'skip',
sort: 'sortBy',
order: 'order'
}
},
filters: {
GET: {
type: 'query-param',
filters: [
{ key: 'status', valueType: 'string', comparison: 'eq' },
{ key: 'minAge', field: 'age', valueType: 'number', comparison: 'gte' }
]
}
}
})Usage:
bash
GET /api/users?status=active&minAge=18&limit=10&skip=0&sortBy=name&order=ascProcessing order:
- Apply filters → Get matching items
- Sort results
- Apply pagination → Return subset
- Return data with
X-Total-Elementsheader
Per-Handler Configuration
Override global config for specific handlers:
typescript
universalApi({
// Global config
pagination: {
GET: {
type: 'query-param',
limit: 'limit',
skip: 'skip'
}
},
handlers: [
{
pattern: '/users',
method: 'GET',
handle: 'FS',
// Override for this handler
pagination: {
type: 'query-param',
limit: 'pageSize', // Different param name
skip: 'offset', // Different param name
sort: 'orderBy',
order: 'direction'
},
filters: {
type: 'query-param',
filters: [
{ key: 'role', valueType: 'string', comparison: 'eq' }
]
}
}
]
})Usage:
bash
GET /api/users?role=admin&pageSize=20&offset=0&orderBy=createdAt&direction=descData Requirements
JSON Array Required
json
// ✅ Works - JSON array
[
{"id": 1, "name": "John"},
{"id": 2, "name": "Jane"}
]
// ❌ Does NOT work - JSON object
{
"users": [
{"id": 1, "name": "John"}
]
}Field Existence
Filter fields must exist in data:
json
// Data
[
{"id": 1, "name": "John", "age": 30},
{"id": 2, "name": "Jane"} // Missing 'age'
]bash
GET /api/users?minAge=25
# Returns: [{"id": 1, "name": "John", "age": 30}]
# Jane is excluded (age field missing)Advanced Examples
Search with Pagination
typescript
filters: {
GET: {
type: 'query-param',
filters: [
{ key: 'q', field: 'name', valueType: 'string', comparison: 'contains' }
]
}
},
pagination: {
GET: {
type: 'query-param',
limit: 'limit',
skip: 'skip'
}
}bash
GET /api/users?q=john&limit=10&skip=0
# Search for 'john', return first 10 resultsMultiple Filters
typescript
filters: {
GET: {
type: 'query-param',
filters: [
{ key: 'status', valueType: 'string', comparison: 'eq' },
{ key: 'role', valueType: 'string', comparison: 'eq' },
{ key: 'verified', valueType: 'boolean', comparison: 'eq' }
]
}
}bash
GET /api/users?status=active&role=admin&verified=true
# All filters must match (AND logic)Range Queries
typescript
filters: {
GET: {
type: 'query-param',
filters: [
{ key: 'minPrice', field: 'price', valueType: 'number', comparison: 'gte' },
{ key: 'maxPrice', field: 'price', valueType: 'number', comparison: 'lte' }
]
}
}bash
GET /api/products?minPrice=10&maxPrice=100
# Returns products where 10 <= price <= 100Limitations
- ❌ Only works with file-based endpoints
- ❌ Only works with JSON arrays (not objects)
- ❌ Does NOT work with custom handlers (must implement manually)
- ❌ No OR logic between filters (only AND)
- ❌ No nested field filtering (e.g.,
user.address.city)
Next Steps
- File-System API - Complete FS guide
- HTTP Methods - Method behavior reference
- Examples - Practical examples
