Version: 1.7.0 Date: May 2026 Status: Draft
Okyline is a JSON-based schema language for validating JSON documents by example. You write a JSON document with real example values, then add constraints directly in field names.
Okyline is a declarative language designed to describe the structure and constraints of JSON documents in a lightweight and readable manner. It enriches JSON examples with inline constraints, enabling data validation while keeping schemas human-friendly.
Okyline was designed from the outset to support structural validation, conditional logic, and computed business invariants within JSON document definitions.
For conditional rules ($requiredIf, $forbiddenIf, $appliedIf, …), see the companion Okyline Core Quick Reference - Conditional Directives.
A minimal Okyline schema:
{
"$oky": {
"name|@": "Alice",
"age|(18..120)": 30
}
}↳ Two fields: name required string, age integer between 18 and 120
" fieldName | constraints | label ": exampleValue
| Part | Required | Description |
|---|---|---|
fieldName |
Yes | JSON attribute name |
constraints |
No | Space-separated constraint symbols |
label |
No | Human-readable description (no \| allowed) |
Example:
"email|@ {5,100} ~$Email~|User email": "alice@example.com"↳ Required string, 5-100 chars, must match email format, labeled “User email”
The example value determines the expected type:
| Example value | Inferred type |
|---|---|
"text" |
String |
42 |
Integer |
3.14 |
Number |
"78.00" |
Number (auto-convert) |
true / false |
Boolean |
[1, 2] |
Array[Integer] |
{"k": "v"} |
Object |
Note: Since JSON serialization doesn’t guarantee trailing zeros are preserved, you can express decimal numbers as strings (e.g., "78.00"). These are auto-converted to Number. Use $str to force string type if needed.
Modifiers: - $str - force string type (disable decimal auto-conversion) - $obj - treat array example as multiple examples of a single-value field
| Symbol | Applies to | Meaning |
|---|---|---|
@ |
All | Required |
? |
All | Nullable |
# |
Scalars | Key field (for uniqueness in lists) |
% |
All | Default value (informational only) |
{max} |
String | Max length |
{min,max} |
String | Length range |
{min,*} |
String | Min only (no max) |
{*} |
String | Any length |
(min..max) |
Number | Inclusive range |
(>n) (<n) (>=n) (<=n) |
Number | Comparison |
('a','b','c') |
All | Enum values |
~pattern~ |
String | Inline regex |
~$Name~ |
String | Named format |
Example combining constraints:
"price|@ ? (0.01..9999.99)": 19.99↳ Required, nullable, decimal between 0.01 and 9999.99
| Syntax | Applies to | Meaning |
|---|---|---|
[max] |
List | Max size |
[min,max] |
List | Size range |
[min,*] |
List | Min only (no max) |
[*] |
List | Any size |
-> constraints |
List/Map | Apply constraints to each element |
! |
List | Uniqueness (by # keys for objects) |
[*:max] |
Map | Any key, max entries |
[*:*] |
Map | Any key, any entries |
[~pattern~:max] |
Map | Key pattern, max entries |
[~pattern~:*] |
Map | Key pattern, any entries |
Examples:
"tags|[1,5] -> {2,20}!": ["eco", "bio"]↳ List of 1-5 unique strings, each 2-20 characters
"scores|[15] -> (0..100)": [85, 92]↳ List of maximum 15 elements, each element between 0 and 100
"translations|[~^[a-z]{2}$~:10] -> {1,100}": { "en": "Hello", "fr": "Bonjour" }↳ Map with 2-letter keys, max 10 entries, values 1-100 characters
"users|[10] -> !": [{ "id|#@": 1, "name|@": "Alice" }]↳ List of max 10 unique objects - uniqueness determined by # key field (id)
Conditions and references can target fields in parent or root objects:
| Prefix | Resolves from |
|---|---|
| (none) | Current object |
this. |
Current object (explicit) |
parent. |
Parent of the current context |
root. |
Document root |
Note: parent skips over arrays - it always refers to the nearest parent object, not the array containing the current item.
Example:
"$requiredIf parent.status('ACTIVE')": ["code"]↳ In a nested object: code required when the parent’s status equals “ACTIVE”
Nomenclature - reusable value lists:
"$nomenclature": { "STATUS": "ACTIVE,INACTIVE,PENDING" }Usage: ($STATUS)
Format - reusable regex patterns:
"$format": { "Phone": "^\\+[0-9]{10,15}$" }Usage: ~$Phone~
| Format | Description |
|---|---|
$Date |
ISO 8601 date (semantic validation) |
$DateTime |
ISO 8601 datetime (semantic validation) |
$Time |
RFC 3339 time |
$Email |
Email address |
$Uri |
URI with scheme |
$Uuid |
UUID v1-v5 |
$Ipv4 |
IPv4 address |
$Ipv6 |
IPv6 address |
$Hostname |
DNS hostname |
Test the runtime type of a field in conditions. Useful when a field can have different types and you need different validation rules for each.
| Guard | Matches |
|---|---|
_String_ |
string |
_Integer_ |
integer (no decimals) |
_Number_ |
number (int or decimal) |
_Boolean_ |
boolean |
_Null_ |
null |
_Object_ |
object |
_EmptyList_, _ListOfString_, _ListOfInteger_, _ListOfNumber_, _ListOfBoolean_, _ListOfObject_, _ListOfNull_ |
array by element type |
Example:
"$appliedIf data": {
"(_String_)":{"data|{5,50}": "Hello"},
"(_Integer_)":{"data|(1..200)": 100}
}↳ data validated as string (5-50 chars) or integer (1-200) depending on its actual type
For fields that accept different structures. For conditional variants, prefer $appliedIf (see Conditional Directives Quick Reference). Use $oneOf/$anyOf when variants are unrelated to other field values.
| Modifier | Meaning |
|---|---|
$oneOf |
Value must match exactly one variant |
$anyOf |
Value must match at least one variant (default) |
Example:
"payment|@ $oneOf": [
{ "type|@ ('card')": "card", "number|@": "1234..." },
{ "type|@ ('paypal')": "paypal", "email|@": "a@b.c" }
]↳ payment expects ONE object matching either card or paypal variant (not an array)
Prefix attribute name with // to ignore it and its entire subtree:
"//user|@": { "id": 1, "name": "ignored" }↳ The entire user object and its children are ignored by the parser
Complete schema with all optional metadata:
{
"$okylineVersion": "1.7.0",
"$version": "1.0.0",
"$title": "My Schema",
"$description": "Schema description",
"$id": "my.schema",
"$state": "DRAFT",
"$additionalProperties": false,
"$sequence": false,
"$nomenclature": { ... },
"$format": { ... },
"$oky": { ... }
}| Key | Required | Purpose |
|---|---|---|
$oky |
Yes | Schema definition |
$okylineVersion |
No | Spec version ("1.7.0") |
$version |
No | Schema version |
$title |
No | Schema title |
$description |
No | Schema description |
$id |
No | Schema identifier |
$state |
No | Lifecycle state: "DRAFT" (default) or "FINAL". No effect on validation. |
$additionalProperties |
No | Allow unknown fields (default: false). Local overrides global. |
$sequence |
No | Enforce field order in validated objects (default: false). Local overrides global. |
$nullAsAbsentIfUndeclared |
No | Treat null on non-? fields as absent (default: false) |
$decimalScale |
No | Decimal precision for numeric comparisons, ranges and computes (default 6) |
$nomenclature |
No | Reusable value lists |
$format |
No | Reusable regex patterns |
Root keys are closed: any unknown $-key at the root fails loading.
See the per-annex Quick References for: $compute (C), $defs (D), external imports & visibility (E), $field (F).
Okyline® is a registered trademark of Akwatype.