Skip to main content
# Validate JSON data using a schema written in Python

# Examples

```
from okschema import validate, ValidationError, SchemaError

try:
validated_data = validate(schema, data)
except ValidationError as e:
print(e.js) # {'code': ValidationCode.<xxx>}
```

## Validation of a simple form
```
from okschema import validate, fmt_uuid

def val_email(v):
return v

schema = {
'my_password': {'@t': 'string', '@lteq': 100},
'user_id': {'@t': 'string', '@regexp': fmt_uuid},
'new_email': {'@t': 'string', '@val': val_email},
'new_password': {'@t': 'string', '@lteq': 100},
}
data = {
'my_password': 'abc',
'user_id': 'dbc8911c-92e8-4cdb-85b8-47a7a6a82db1',
'new_email': 'abc@example.com',
'new_password': 'abc'
}
validated_data = validate(schema, data)
```

## Potential use in request handling

```
@api_request(schema=lambda m: {
'email': {'@t': 'string', '@lteq': m.user.c.email.ui_len},
'password': {'@t': 'string', '@lteq': m.user.c.password.ui_len},
'key': {'@t': 'string', '@lteq': 10240},
'permission_level': {'@t': 'int', '@in': [PermissionE.ADMIN, PermissionE.USER]},
})
async def add_user_account(request, m):
...
```

## Nested structure - error handling
```
schemaA = {
'outer': {
'a': 'int',
'b': {'@t': 'str', '@lt': 2, '@optional': True, '@null': True, '@blank': True},
'c': [{'@t': 'str', '@in': ['x', 'y', 'z']}]
},
'is_ok': {'@type': 'bool', '@default': True}
}
data1 = {
}
data2 = {
'outer': {
'a': 'xxx',
'b': '3333',
'c': ['a', 'x', 12]
},
'is_ok': True
}
```

```
>>> validate(schemaA, data1)
ValidationError: ({
'outer': {'code': ValidationCode.MISSING},
'is_ok': {'code': ValidationCode.MISSING}
}, schemaA)
```

```
>>> validate(schemaA, data2)
ValidationError: ({
'outer': {
'a': {'code': ValidationCode.BAD_TYPE},
'b': {'code': ValidationCode.NOT_LT, 'details': 2},
'c': [
{'code': ValidationCode.NOT_IN},
None, # no error here
{'code': ValidationCode.BAD_TYPE}
]
},
'is_ok': {'code': ValidationCode.BAD_TYPE}
), schemaA)
```

## Custom validators - error handling

```
def bad_val1_cont(x):
raise NotValidButContinueError(ValidationCode.BAD_VALUE, 1)

def bad_val2_cont(x):
raise NotValidButContinueError(ValidationCode.BAD_VALUE, 5)

def bad_val3(x):
raise NotValidError(ValidationCode.BAD_VALUE)

schemaA = {
'b': {'@t': 'int', '@val': [bad_val1_cont, bad_val2_cont]}
}
schemaB = {
'b': {'@t': 'int', '@val': [bad_val1_cont, bad_val2_cont, bad_val3]}
}
data1 = {'b': 12}
```

```
>>> validate(schemaA, data1)
ValidationError: ({
'b': {
'code': ValidationCode.MANY_ERRORS, 'details': [
{'code': ValidationCode.BAD_VALUE, 'details': 1},
{'code': ValidationCode.BAD_VALUE, 'details': 5}
]
}
}, schemaA)

>>> validate(schemaB, data1)
ValidationError: ({
'b': {
'code': ValidationCode.MANY_ERRORS, 'details': [
{'code': ValidationCode.BAD_VALUE, 'details': 1},
{'code': ValidationCode.BAD_VALUE, 'details': 5},
{'code': ValidationCode.BAD_VALUE}
]
}
}, schemaA)
```

# ValidationCode enum

BAD_TYPE = 1
NOT_IN = 2
NULL = 3
MISSING = 4
OUT_OF_BOUNDS = 5 # for use by validators
REGEXP = 6
MANY_ERRORS = 8 # list of errors for a single field
NOT_GT = 9
NOT_GTEQ = 10
NOT_LT = 11
NOT_LTEQ = 12
NOT_EQ = 13

# Field description
```
"field: "type"
"field": { extended field description }
```

# Extended field description
By default all fields are required and strings must be non-empty. Extra fields in input data are discarded.
```
{
"@t": "type", # default type is dict

# -- validators --

# Checks that regexp matches - called before other validators.
"@regexp": "regexp",

# Validator function.
"@val": val_fun,
"@val: [val_fun, val_fun2, ...],

# -- options --

# If True and value is missing, it will not be present in result unless
# default is defined. Makes sense for subfields in dicts.
"@optional": bool,

# Allows empty strings.
"@blank": bool,

# Used when value is not present.
# Default value is never passed to validators.
"@default": value,

# Allow nulls (None). By default null is not allowed.
"@null": bool,

# -- limits --
# Checked before validators are called.
# They work for string lengths too.
# TODO: They work for list lengths too.

"@in": [value1, value2, ...],
"@gt": value,
"@gteq": value,
"@lt": value,
"@lteq": value,
"@neq": value,

# Extra fields if type is dict.
"field1": field description or extended field description,
...
}
```

# Lists.

```
"field": [field description]
"field": [{extended field description}]
```

## TODO: Optional lists.

## TODO: List length limits.
```
"field": [
{
# field description
}, {
# list parameters
"@optional": True,
"@gt": val,
}
]
```

# Available types
## scalar
- string (str)
- int
- decimal
- float
- bool

## composite
- dict

## TODO: Type "any" handles any type of subjson withot further validation

# Validator functions

```
def fun(val):
return val + 1
```

Should either return validated value or raise NotValidError(code, details).
May also raise NotValidButContinueError to store the error but call the next validator, constructing a list
of errors.

Metadata

Release files for okschema 0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for okschema 0.2
File Size Uploaded
okschema-0.2.tar.gz 6.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for okschema 0.2
File Interpreter ABI Platform
okschema-0.2-py2-none-any.whl Python 2 none any Details

Total release size: 12.4 kB

Release files / okschema-0.2.tar.gz

Download URL okschema-0.2.tar.gz
Size 6.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ea4c3196d5f4be0b367e4fed3234c4e5c3f8417807632984b81ead66532b897c
BLAKE2b-256 checksum
How to use checksums
4cd2b0320701cc1422d94f05b8eedfac79f93563d2e7e69420e069662cb73932
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Python-urllib/2.7

Release files / okschema-0.2-py2-none-any.whl

Download URL okschema-0.2-py2-none-any.whl
Size 6.3 kB
Tags Python 2
SHA-256 checksum
How to use checksums
b024850706de849022451a8a3b6b3917724c7665fcf6c11f11bce29f55f8bf38
BLAKE2b-256 checksum
How to use checksums
2164797a19a2f71460c0e89b5a628c4279aef0336ceca9cfccc1ef4cb419e832
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Python-urllib/2.7

Release history Release notifications | RSS feed

This release

0.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page