QscSearchRequestValidationFilter
This filter validates incoming search requests in the search pipeline. It checks fields, parameters, and filters using configurable rules with a readable string syntax. When validation fails, it returns a structured error response with individual error items.
Rules can be configured in two places:
- Pipeline YAML — static rules shared across all search apps
- Search config — per-search-app rules configured in the admin
Pipeline rules are applied first, then search config rules.
Base Defaults and Validation
The QscSearchRequestValidationFilter extends SearchQueryValidationFilter from qsf-integration. The base filter applies defaults and validates basic query structure automatically.
Base Defaults
The following defaults are applied to all filters before any validation or configurable rules run:
| Property | Default |
|---|---|
name | set to the filter id |
filterType | term |
filterDataType | string |
filterOperator | or |
Base Validation
| Check | Error |
|---|---|
page < 0 | The page must be >= 0. |
rows < 0 | The rows must be >= 0. |
Filter missing id | A search filter is missing an id. |
term/match filter without values | The filter 'x' of type term must have at least one value. |
range/slider filter without range value | The filter 'x' of type range must have a range value or values. |
| Numeric range with non-parseable value | The filter 'x' has a non-numeric min value: abc |
These defaults and checks always run. No configuration needed.
If you only need the base validation without configurable rules, you can use SearchQueryValidationFilter directly:
- !!com.quasiris.qsf.pipeline.filter.SearchQueryValidationFilter
active: true
id: search-pipeline.SearchQueryValidationFilter
Pipeline Configuration
- !!com.quasiris.qsc.search.service.QscSearchRequestValidationFilter
active: true
id: search-pipeline.QscSearchRequestValidationFilter
rules:
- "locale: required"
- "q: required, minLength=1, maxLength=500"
- "requestId: required"
- "userId: required"
- "sessionId: required"
- "requestOrigin: required"
- "page: min=0, max=100, default=1"
- "rows: min=0, max=100, default=10"
The filter should be placed early in the pipeline, typically after QscSearchQueryFilter and before QueryRuleFilter.
Search Config
Rules can also be configured per search app in the search config via the validation object:
{
"validation": {
"rules": [
"q: required, minLength=1, maxLength=500",
"parameter.customerId: required, type=integer",
"rows: max=50"
]
}
}
Search config rules are merged with pipeline rules at runtime. Pipeline rules run first, then search config rules. The same string syntax applies to both. See the Search Config documentation for details.
Rule Syntax
Each rule is a string with the format:
target: constraint1, constraint2, ...
There are three categories of rules:
| Category | Format | Description |
|---|---|---|
| Field | fieldName: constraints | Validates a standard search query field |
| Parameter | parameter.name: constraints | Validates a parameter from the parameters map |
| Filter | filter.id: constraints | Validates a search filter from the filter list |
Standard fields (q, locale, page, rows, requestId, userId, sessionId, requestOrigin) use no prefix. Only parameter. and filter. require a prefix.
Field Rules
Validate standard fields on the search query.
| Constraint | Description | Example |
|---|---|---|
required | Field must be non-null and non-blank | locale: required |
values | Field value must be one of the listed values (separated by |) | locale: values=de|en|fr |
minLength | Minimum string length | q: minLength=1 |
maxLength | Maximum string length | q: maxLength=500 |
min | Minimum numeric value | page: min=0 |
max | Maximum numeric value | page: max=100 |
default | Default value if field is null (applied before validation) | page: default=1 |
Supported fields
q, locale, requestId, userId, sessionId, requestOrigin, page, rows
Examples
rules:
- "locale: required, values=de|en|fr"
- "q: required, minLength=1, maxLength=500"
- "page: min=0, max=100, default=1"
- "rows: min=0, max=100, default=10"
Multiple rules can be defined for the same field. Each rule is evaluated independently:
rules:
- "q: required, message=q is required"
- "q: minLength=1, message=The minimum length is 1"
- "q: maxLength=500, message=The maximum length is 500"
Parameter Rules
Validate parameters from the parameters map on the search query. Use the parameter. prefix.
| Constraint | Description | Example |
|---|---|---|
required | Parameter must be present | parameter.customerId: required |
values | Value must be one of the listed values (separated by |) | parameter.sort: values=relevance|price|name |
type | Data type check: string, integer, long, double, boolean | parameter.limit: type=integer |
type (array) | Append [] to require an array; each element is type-checked | parameter.ids: type=integer[] |
pattern | Regex pattern match (applied per element for arrays) | parameter.email: pattern=^[\w@.]+$ |
default | Default value if parameter is missing (applied before validation) | parameter.sort: default=relevance |
For array parameters, values, type, and pattern constraints are applied to each element individually. Errors include the array index (e.g. parameter.ids[2]).
If type uses [] but the value is not an array, an error is produced. Conversely, if type does not use [] and the value is an array, an error is produced.
Examples
rules:
# single-value parameters
- "parameter.customerId: required, type=integer"
- "parameter.sort: values=relevance|price|name, default=relevance"
- "parameter.email: required, pattern=^[\\w@.]+$"
- "parameter.verbose: type=boolean"
# array parameters
- "parameter.ids: required, type=integer[]"
- "parameter.tags: type=string[], values=featured|sale|new"
Filter Rules
Validate search filters from the filter list. Use the filter. prefix.
Basic filter syntax validation (values present for term filters, range value present for range filters, numeric parsing) is already handled by the base SearchQueryValidationFilter. These rules add additional constraints like requiring specific filters or enforcing types.
| Constraint | Description | Example |
|---|---|---|
required | Filter must be present in the request | filter.category: required |
values | Every filter value must be one of the listed values (separated by |) | filter.color: values=red|green|blue |
type | Expected filter type: term, match, range, slider, etc. | filter.category: type=term |
dataType | Expected data type: string, number, date | filter.price: dataType=number |
default | Creates the filter with this term value if missing | filter.category: default=all |
defaultType | Sets filter type if null | filter.price: defaultType=range |
defaultDataType | Sets data type if null | filter.price: defaultDataType=number |
defaultOperator | Sets operator if null | filter.category: defaultOperator=and |
Examples
rules:
- "filter.category: required, type=term"
- "filter.price: type=range, dataType=number"
# restrict allowed values
- "filter.color: values=red|green|blue"
# create a default filter if not present in the request
- "filter.status: default=active"
# set default type/dataType on an existing filter
- "filter.price: defaultType=range, defaultDataType=number"
Default Values
Rules can specify default values that are applied before validation runs. This means a field with required and default will never fail the required check -- the default is set first.
Field and Parameter Defaults
Use default=<value> to set a value when the field or parameter is null/missing.
rules:
# field defaults
- "page: min=0, max=100, default=1"
- "rows: min=0, max=100, default=10"
- "locale: required, default=de"
# parameter defaults
- "parameter.sort: default=relevance"
For numeric fields (page, rows), the default value string is parsed as an integer. For locale, it is parsed via Locale.forLanguageTag() (e.g. de, en-US).
Filter Defaults
Filters support several default constraints:
| Constraint | Description |
|---|---|
default=<value> | If the filter is not present, creates a new term filter with this value |
defaultType=<type> | Sets the filter type if null (e.g. term, range, slider) |
defaultDataType=<type> | Sets the data type if null (e.g. string, number, date) |
defaultOperator=<op> | Sets the operator if null (e.g. or, and) |
When default=<value> creates a new filter, it uses term type, string data type, and or operator by default. You can override these with defaultType, defaultDataType, and defaultOperator on the same rule.
rules:
# create a term filter with value "active" if not in the request
- "filter.status: default=active"
# create a range filter with default value
- "filter.price: default=0, defaultType=range, defaultDataType=number"
# set default properties on existing filters (no-op if filter is absent)
- "filter.category: defaultOperator=and"
Custom Messages and Status Codes
Any rule can have an optional message and statusCode:
| Option | Description | Default |
|---|---|---|
statusCode=<code> | HTTP status code for the error response | 400 |
message=<text> | Custom error message (replaces the auto-generated one) | auto-generated |
message= must be the last constraint in the rule, because its value extends to the end of the string and can contain commas.
Examples
rules:
# custom message
- "q: required, message=The search query is required"
# custom status code and message
- "page: min=0, max=100, statusCode=422, message=Page number is out of range"
# message with commas
- "parameter.token: required, statusCode=403, message=Access token is required, please authenticate first"
Error Response
When one or more rules fail, the filter returns a structured error response using the FullValidationMessage format from qsc-dto. Each violation is returned as a separate item in the errors array:
{
"timestamp": "2026-03-09T10:30:00.000Z",
"requestId": "a1b2c3d4-...",
"status": 400,
"errors": [
{
"errorGroup": "field",
"field": "locale",
"message": "The field 'locale' is required.",
"errorCode": "required"
},
{
"errorGroup": "field",
"field": "q",
"message": "The field 'q' is required.",
"errorCode": "required"
}
]
}
Each error includes:
| Property | Description |
|---|---|
errorGroup | Always field |
field | The target: field name, parameter.name, or filter.id |
message | Human-readable error description (or custom message from rule) |
errorCode | Constraint that failed: required, values, minLength, maxLength, min, max, type, dataType, pattern, validation |
When a rule specifies a custom message, it replaces the auto-generated one:
{
"timestamp": "2026-03-09T10:30:00.000Z",
"requestId": "a1b2c3d4-...",
"status": 422,
"errors": [
{
"errorGroup": "field",
"field": "q",
"message": "The search query is required",
"errorCode": "required"
}
]
}
Full Example
Pipeline YAML
- !!com.quasiris.qsc.search.service.QscSearchRequestValidationFilter
active: true
id: search-pipeline.QscSearchRequestValidationFilter
rules:
# required fields with allowed values
- "locale: required, values=de|en|fr"
- "q: required, message=The search query is required"
- "q: minLength=1, message=The search query must not be empty"
- "q: maxLength=500, message=The search query is too long"
- "requestId: required"
- "userId: required"
- "sessionId: required"
- "requestOrigin: required"
# paging with defaults
- "page: min=0, max=100, default=1"
- "rows: min=0, max=100, default=10"
# filters
- "filter.category: required, type=term"
- "filter.price: type=range, dataType=number"
Search Config
Additional rules per search app, configured in the admin:
{
"validation": {
"rules": [
"parameter.customerId: required, type=integer, message=A valid customer ID is required",
"rows: max=50",
"filter.status: default=active"
]
}
}