Skip to main content

Validate JSON data using a schema written in Python

Project description

# 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

okschema-0.2.tar.gz (6.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

okschema-0.2-py2-none-any.whl (6.3 kB view details)

Uploaded Python 2

File details

Details for the file okschema-0.2.tar.gz.

File metadata

  • Download URL: okschema-0.2.tar.gz
  • Upload date:
  • Size: 6.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Python-urllib/2.7

File hashes

Hashes for okschema-0.2.tar.gz
Algorithm Hash digest
SHA256 ea4c3196d5f4be0b367e4fed3234c4e5c3f8417807632984b81ead66532b897c
MD5 719d489c6f6869620a5607917c57a44d
BLAKE2b-256 4cd2b0320701cc1422d94f05b8eedfac79f93563d2e7e69420e069662cb73932

See more details on using hashes here.

File details

Details for the file okschema-0.2-py2-none-any.whl.

File metadata

  • Download URL: okschema-0.2-py2-none-any.whl
  • Upload date:
  • Size: 6.3 kB
  • Tags: Python 2
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Python-urllib/2.7

File hashes

Hashes for okschema-0.2-py2-none-any.whl
Algorithm Hash digest
SHA256 b024850706de849022451a8a3b6b3917724c7665fcf6c11f11bce29f55f8bf38
MD5 e705a594e2a90dd6f6fdb5b710d105a9
BLAKE2b-256 2164797a19a2f71460c0e89b5a628c4279aef0336ceca9cfccc1ef4cb419e832

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page