compare
Generic schema-driven comparison validator.
compare is an enterprise-safe, contract-driven comparison rule whose semantics are derived exclusively from the
schema type/format at the validation attachment point.
Applicable To: property
Supported operators
- Binary comparisons:
<,<=,>,>=,=,!=,<> - Set/range comparisons:
in— right-hand side is an array of allowed valuesbetween— right-hand side represents an inclusive min/max bound
Normalized/case-insensitive string comparison
When comparing strings for equality (=, !=, <>), you can enable normalization (trimming and lowercasing) by setting the normalize: true or caseInsensitive: true parameter. This allows for case-insensitive and whitespace-insensitive comparisons, replacing the previous normalizedEquals validator.
Example:
confirmEmail:
type: string
x-validations:
- function: compare
parameters:
operator: "="
field: email
normalize: true
This will pass if confirmEmail and email match after trimming and lowercasing both values.
Operand sources
Right-hand side operand must be supplied via exactly one of:
value: a literal comparison value (or anow...token)field: the name/path to another field in the same object (currently top-level property name)
Schema-driven typing (no explicit datatype parameter)
compare determines comparison semantics strictly from the resolved OpenAPI schema:
Numeric
type: numberortype: integer- Values are coerced to numbers.
- If coercion fails:
- Left-hand side coercion failure is a data error.
- Right-hand side coercion failure is a definition error.
Special numeric values (integer/number only)
now(year)(case-insensitive) may be used to represent the current year.now(year)±<n>ymay be used to offset that year (e.g.,now(year)-50y,now(year)+1y).
Notes - Only
now(year)is supported for numeric comparisons. - Only they(years) unit is supported withnow(year).
Date / date-time
type: stringwithformat: date-timeorformat: date- Values are parsed as RFC 3339 / ISO-8601 using JavaScript date parsing.
- If parsing fails, validation fails.
Special datetime values (for format: date-time and format: date only)
value (or the resolved field) may be:
now(case-insensitive)now(year)— truncate current datetime to the start of the yearnow(month)— truncate current datetime to the start of the monthnow(day)— truncate current datetime to the start of the day
Relative now offsets (date/date-time)
You can offset now (and truncated now(...)) using:
now±<n><unit>now(<truncate>)±<n><unit>
Where <unit> is one of:
y(years)mo(months)d(days)
Examples:
now-18ynow-2monow(day)+7d
Time
type: stringwithformat: time- Values must match RFC3339 partial-time:
HH:MM:SSwith optional fractional seconds. - Comparison is done by time-of-day.
- Values must match RFC3339 partial-time:
Unsupported
Any other schema type/format combination is rejected. Plain lexicographic string comparison is not allowed unless explicitly supported by schema format.
Coercion rules
- Datetime: must parse as RFC 3339 / ISO-8601 (invalid parses fail with 422)
- Numeric: must coerce to a finite number (invalid coercion fails with 422)
- No silent fallback: invalid RHS/LHS parsing causes validation failure
- No cross-type comparisons: behavior is driven by schema only
Status codes
Status codes are applied centrally by the validation execution pipeline:
422— input fails validation OR rule definition is invalid/unsupported500— reserved for outbound HTTP dependency failures only (not used bycompare)
Examples
1) Field comparison
startDate:
type: string
format: date
x-validations:
- function: compare
parameters:
operator: "<"
field: endDate
2) Compare to a fixed date
manufactureDate:
type: string
format: date
x-validations:
- function: compare
parameters:
operator: ">="
value: "2020-01-01"
3) Compare to now (date/date-time)
createdAt:
type: string
format: date-time
x-validations:
- function: compare
parameters:
operator: "<="
value: now
4) Compare to truncated now
createdAt:
type: string
format: date-time
x-validations:
- function: compare
parameters:
operator: ">="
value: "now(day)"
5) Age check (must be at least 18 years old)
birthDate:
type: string
format: date
x-validations:
- function: compare
parameters:
# birthDate must be on/before now minus 18 years
operator: "<="
value: "now-18y"
6) Recency check (must be within last 2 months)
lastUpdatedAt:
type: string
format: date-time
x-validations:
- function: compare
parameters:
# must be on/after now minus 2 months
operator: ">="
value: "now-2mo"
7) Membership (in)
Note:
inworks for numeric/date/date-time/time schemas. Plain strings without a supported format are intentionally rejected.
hourOfDay:
type: string
format: time
x-validations:
- function: compare
parameters:
operator: in
value: [ "09:00:00", "17:00:00" ]
8) Range (between)
age:
type: number
x-validations:
- function: compare
parameters:
operator: between
value: [ 18, 65 ]
9) Model year range (integer year between 50 years ago and 1 year in the future)
year:
type: integer
x-validations:
- function: compare
parameters:
operator: ">="
value: "now(year)-50y"
- function: compare
parameters:
operator: "<="
value: "now(year)+1y"
10) Not equal
statusChangedAt:
type: string
format: date-time
x-validations:
- function: compare
parameters:
operator: "!="
value: "now(day)"
11) Case-insensitive/normalized string equality
username:
type: string
x-validations:
- function: compare
parameters:
operator: "="
value: "ADMIN"
caseInsensitive: true
This will pass if username is any case/whitespace variant of ADMIN (e.g., admin, Admin, etc).
Note: The previous normalizedEquals validator is now deprecated. Use compare with normalize: true or caseInsensitive: true for all normalized string equality checks.