The latest Okyline release adds declarative constraints for arrays, covering business‑key uniqueness, chronological ordering, first‑element invariants, and cross‑collection consistency. The article walks through a delivery‑tracking example, explains the underlying compute model, and shows how these rules affect API contracts, consistency guarantees, and scalability.
Okyline Extends List Validation with Uniqueness, Ordering, and Cross‑Element Rules
In the fourth installment of the Okyline series, the author demonstrates how the framework can enforce sophisticated constraints on JSON arrays. The examples revolve around a delivery‑tracking payload, but the patterns apply to any domain where ordered events, unique identifiers, or cross‑field invariants matter.
The problem: arrays are easy to misuse
A plain JSON contract can describe the shape of a payload, but it cannot prevent logical errors such as:
- Two SHIPPED steps appearing in the same
trackingStepsarray. - Timestamps that jump backwards, breaking the chronological flow of events.
- An
actualStepfield that does not match the last step recorded. - A boolean flag (
isShipped) that disagrees with the presence of a SHIPPED entry.
Traditional JSON Schema offers uniqueItems, but it only checks whole‑object equality. That means two objects with the same step value but different timestamps would slip through, even though business rules require a single occurrence per step.
Solution approach: declarative list rules in Okyline
Okyline introduces three key operators for array validation:
| Operator | Purpose | Example |
|---|---|---|
! (uniqueness) |
Enforces that each element is unique by a business key. | `trackingSteps |
# (business key) |
Marks the field that determines uniqueness. | `step |
Compute expressions ($compute) |
Attach arbitrary logic that can reference the current element, its neighbours, or the whole collection. | `StepsChronological: "isFirst |
Step‑by‑step validation
No duplicate steps – The
#marker onsteptells Okyline to treat thestepvalue as the uniqueness key. The surrounding!makes the engine reject any second occurrence of the same step, regardless of other fields.Chronological order – Inside each element, a compute expression can reference
isFirstandprev. The ruleisFirst || timestamp > prev.timestampguarantees a strictly increasing timeline.First‑element invariant – A compute attached to the array itself (
(%FirstIsCreated)) can usefirstandsizeto assert that the first step is alwaysCREATED.Cross‑collection checks – Functions like
lastOfandexistslet sibling fields (actualStep,isShipped) be validated against the whole list. For example,actualStep == lastOf(trackingSteps).stepensures the reported current step matches the last recorded event.

Trade‑offs and scalability considerations
Consistency model
Okyline’s validation runs synchronously at the API gateway or service boundary. Because the rules are pure functions over the incoming payload, they provide strong consistency for the contract: a request either passes all checks or is rejected with a precise error. This is a contrast to eventual‑consistency approaches where duplicate steps might be tolerated and corrected later.
Performance impact
The engine evaluates each rule per element and may scan the entire array for functions like exists or countIf. In practice, the cost is linear in the number of elements (O(n)). For typical e‑commerce tracking arrays (under 20 items) the overhead is negligible. However, if a contract were to validate large logs (thousands of entries), you would want to:
- Limit the allowed array size (
[1,10]in the example). - Prefer indexed look‑ups (
existswith a predicate) over full scans when possible. - Cache derived values (e.g., the last step) if the same payload is processed by multiple downstream services.
API design patterns
The article highlights two complementary patterns for exposing validation logic to clients:
- External query style – Compute functions are attached to sibling fields, treating the array as an argument. This mirrors a read‑only API where the client sends data and receives a boolean or error code.
- Internal iteration style – Compute expressions live inside the element definition, allowing each item to validate itself against neighbours. This pattern aligns with PATCH‑style updates where a single step is added to an existing list.
Both patterns can be combined, offering flexibility in how services expose their contracts. A microservice that only accepts incremental updates might rely on the internal iteration checks, while a bulk‑import endpoint would use the external query style to validate the whole payload in one pass.
What this means for developers
- Declarative safety – You no longer need custom middleware to enforce “no duplicate SHIPPED steps”. The rule lives in the contract and is versioned alongside the API.
- Clear error locations – Okyline points to the exact array index and rule that failed, simplifying debugging for front‑end teams.
- Portable contracts – Because the validation description is pure JSON, the same contract can be used by JavaScript, Go, or Python validators without code duplication.
Next steps
The series promises a look at virtual fields—computed values that do not exist in the payload but can drive conditional logic (e.g., loyalty tier calculations). Those fields will further reduce the need for ad‑hoc server‑side checks.
For readers who want to experiment, the full contract is available on the Okyline documentation site. You can paste it into the online validator, tweak the trackingSteps, and watch the engine emit targeted error messages.
This article is part of the "Okyline — JSON validation by example" series, built by Akwatype.

Comments
Please log in or register to join the discussion