Dynamic Search
How to use the dynamic search endpoints available on all CRUD resources.
Dynamic Search
Every resource that extends the base CRUD controller exposes two dynamic search endpoints:
- GET
/{resource}/dynamic-search— query parameters - POST
/{resource}/dynamic-search— request body
Both return a paginated Page<T> response.
Query Parameters (GET)
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 0 | Zero-based page number |
size | integer | 20 | Results per page (max 100) |
search | string[] | [] | Search criteria in field:value format |
filters | string[] | [] | Filter criteria (see Filter Operators) |
sort | string | — | Sort expression (see Sorting) |
Example
GET /products/dynamic-search?search=name:table&search=id:table&filters=status:active&sort=created:desc&page=0&size=20Request Body (POST)
{
"search": ["name:table", "id:table"],
"filters": {
"status": "active",
"subsidiaryId": "SUB-001"
},
"sort": [
{ "field": "created", "ascending": false }
],
"page": 0,
"size": 20
}The POST variant accepts filters as a map (key-value object) and sort as a list of objects with field and ascending properties.
Search
The search parameter accepts an array of strings in field:value format. Each entry tells the backend which field to search and what text to look for.
search=name:wooden table&search=id:wooden tableThis searches for "wooden table" in both the name and id fields.
How matching works
- Multiple search entries are combined with OR — a result matches if any field contains the text.
- Multi-word values use AND within the field — all words must appear (in any order).
- Matching is case-insensitive and uses regex.
For example, search=name:oak table matches products where the name contains both "oak" and "table" (e.g. "Solid Oak Dining Table").
Filter Operators
Filters support exact matching and comparison operators.
Simple filter
filters=status:activeMatches documents where status equals "active".
Operator filter
Use the three-part format field:operator:value:
| Operator | Aliases | Description | Example |
|---|---|---|---|
in | — | Match any value in a comma-separated list | status:in:active,pending,draft |
gte | >= | Greater than or equal | price:gte:100 |
lte | <= | Less than or equal | price:lte:500 |
gt | > | Greater than | quantity:gt:0 |
lt | < | Less than | quantity:lt:50 |
Value coercion
Filter values are automatically coerced:
| Input | Coerced type |
|---|---|
"null" | null |
"true" / "false" | Boolean |
"42" | Integer |
"3.14" | Double |
| anything else | String |
Combining filters
Filters are combined with AND — all filters must match. Filters and search are also combined with AND.
filters=status:active&filters=price:gte:100&search=name:chairThis returns items where status is active AND price >= 100 AND name contains "chair".
Sorting
Single sort
sort=created:descDirection defaults to ascending if omitted:
sort=nameMultiple sorts
Separate multiple sort expressions with a semicolon:
sort=status:asc;created:descResponse
All dynamic search endpoints return a standard Spring Page<T>:
{
"content": [...],
"totalElements": 142,
"totalPages": 8,
"number": 0,
"size": 20
}CSV Export
The same parameters work with the CSV export endpoint:
GET /{resource}/csv-export?search=name:table&filters=status:active&sort=created:descThis returns a ByteArray response with Content-Type: text/csv.
Frontend Helpers
The frontend provides helper functions to build dynamic search parameters from table UI state.
tableDynamicSearchBuilder
Converts table pagination state into API query parameters.
import { tableDynamicSearchBuilder } from "@/shared/components/table/functions/tableDynamicSearchBuilder";
const params = tableDynamicSearchBuilder<Product>(
updater, // pagination state from table
["name", "id"], // fields to search
{ status: "active" } // optional filters
);
// Result: { page, size, search: ["name:text", "id:text"], sort, filters, direction }dynamicSearchFilterBuilder
Converts a filter object into the string[] format.
import { dynamicSearchFilterBuilder } from "@/shared/functions/shared/dynamicSearchFilterBuilder";
const filters = dynamicSearchFilterBuilder<Product>({
status: "active",
category: "furniture",
name: "", // empty values are excluded
});
// Result: ["status:active", "category:furniture"]extractSearchText
Extracts the original search text from a dynamic search array (useful for populating the search input).
import { extractSearchText } from "@/shared/components/table/functions/tableDynamicSearchBuilder";
extractSearchText(["name:wooden table", "id:wooden table"]);
// Result: "wooden table"Route integration
Routes validate search params using the dynamicPaginationSchema:
import { dynamicPaginationSchema } from "@/shared/schemas/shared";
export const Route = createFileRoute("/_app/products/")({
validateSearch: z.object({
page: dynamicPaginationSchema,
}),
});