Filter, sort, and paginate any collection endpoint straight from the URL. The parameters match json-server, so anything you already know works here — no config, no setup, and nothing to define per endpoint.
GET https://acme.mockmydata.io/api/products?category=tools200 OK · X-Total-Count: 4
[
{
"id": 1,
"name": "Cordless Drill",
"category": "tools",
"price": 129.99,
"inStock": true
},
{
"id": 2,
"name": "Hammer",
"category": "tools",
"price": 24.5,
"inStock": true
},
{
"id": 4,
"name": "Drill Bit Set",
"category": "tools",
"price": 45,
"inStock": true
},
{
"id": 6,
"name": "Circular Saw",
"category": "tools",
"price": 189,
"inStock": true
}
]4 of 4 rows. X-Total-Count always reports the count before pagination, so you can size your pager.
Any parameter without an underscore prefix filters on a field. The two spellings below are interchangeable — every operator accepts both, and they return identical results.
| Operator | Underscore | Colon | What it does |
|---|---|---|---|
| Equals | category=tools | category=tools | Field matches exactly |
| Not equal | category_ne=tools | category:ne=tools | Field is anything else |
| Greater than | price_gt=50 | price:gt=50 | Numbers and ISO dates |
| Greater or equal | price_gte=50 | price:gte=50 | Inclusive lower bound |
| Less than | price_lt=50 | price:lt=50 | Numbers and ISO dates |
| Less or equal | price_lte=50 | price:lte=50 | Inclusive upper bound |
| Contains | name_like=drill | name:contains=drill | Substring, case-insensitive |
| Starts with | name_startswith=Cord | name:startswith=Cord | Case-insensitive prefix |
| Ends with | name_endswith=Set | name:endswith=Set | Case-insensitive suffix |
| In list | id_in=1,2,3 | id:in=1,2,3 | Matches any value listed |
?category=tools&price_gte=50?id=1&id=3?vendor.name=Bosch_like and _contains are two names for the same operator.These start with an underscore so they can never collide with a field actually named sort or page.
| Parameter | Example | What it does |
|---|---|---|
| _page | _page=2 | Page number, starting at 1. Defaults to 10 per page. |
| _limit | _limit=25 | Rows per page. Capped by your plan. |
| _per_page | _per_page=25 | Same as _limit. json-server v1 spelling. |
| _sort | _sort=-price | Sort field. Prefix with - for descending. Comma-separate for multiple. |
| _order | _order=desc | asc or desc. Pairs with _sort, positionally for multiple fields. |
| q | q=drill | Full-text across every top-level string and number field. |
Rows per request are capped at 100 on the free plan and 1,000 on Pro. Ask for more and you get the cap, not an error.
This is the point: the fetch you write against the mock is the fetch you keep when the real backend lands. Nothing to delete at swap time.
const params = new URLSearchParams({
_page: String(page),
_limit: "20",
_sort: "-createdAt",
category,
});
const res = await fetch(`${API_URL}/api/products?${params}`, {
headers: { "X-API-Key": key },
});
const total = Number(res.headers.get("X-Total-Count"));
const rows = await res.json();
setPageCount(Math.ceil(total / 20));Try it on your own data
Create an endpoint and every parameter above works on it immediately.