jsonweb.schema

jsonweb.schema provides a layer of validation before json.decode returns your object instances. It can also be used simply to validate the resulting python data structures returned from json.loads(). Here is an example of validating the structure of a python dict:

>>> from jsonweb.schema import ObjectSchema, ValidationError
>>> from jsonweb.schema.validators import String

>>> class PersonSchema(ObjectSchema):
...     first_name = String()
...     last_name = String()
    
>>> try:
...     PersonSchema.validate({"first_name": "shawn"})
... except ValidationError, e:
...     print e.errors
{"last_name": "Missing required parameter."}

Validating plain old python data structures is fine, but the more interesting exercise is tying a schema to a class defination:

>>> from jsonweb.decode import from_object, loader
>>> from jsonweb.schema import ObjectSchema, ValidationError
>>> from jsonweb.schema.validators import String, Integer, EnsureType

>>> class PersonSchema(ObjectSchema):
...    id = Integer()
...    first_name = String()
...    last_name = String()
...    gender = String(optional=True)
...    job = EnsureType("Job")

You can make any field optional by setting optional to True.

Warning

The field is only optional at the schema level. If you’ve bound a schema to a class via from_object() and the uderlying class requires that field a ObjectAttributeError will be raised if missing.

As you can see its fine to pass a class name as a string, which we have done for the Job class above. We must later define Job and decorate it with jsonweb.decode.from_object()

>>> class JobSchema(ObjectSchema):
...    id = Integer()
...    title = String()    

>>> @from_object(schema=JobSchema)
... class Job(object):
...     def __init__(self, id, title):
...         self.id = id
...         self.title = title

>>> @from_object(schema=PersonSchema)
... class Person(object):
...     def __init__(self, first_name, last_name, job, gender=None):
...         self.first_name = first_name
...         self.last_name = last_name
...         self.gender = gender
...         self.job = job
...     def __str__(self):
...         return '<Person name="%s" job="%s">' % (
...             " ".join((self.first_name, self.last_name)),   
...             self.job.title
...         )

>>> person_json = '''
...     {
...         "__type__": "Person",
...         "id": 1,    
...         "first_name": "Bob",
...         "last_name": "Smith",
...         "job": {"__type__": "Job", "id": 5, "title": "Police Officer"},
...     }
... '''

>>> person = loader(person_json)
>>> print person
<Person name="Bob" job="Police Officer">

ValidationErrors

class jsonweb.schema.ValidationError(message, errors=None)

Validators

Validators for use in jsonweb.schema.

class jsonweb.schema.validators.String(max_len=None, **kw)

Validates something is a string

>>> String().validate("foo")
... 'foo'
>>> String().validate(1)
Traceback (most recent call last):
    ...
ValidationError: Expected str got int instead.

You can also specify a maximum string length

>>> String(max_len=3).validate("foobar")
Traceback (most recent call last):
...
ValidationError: String exceeds max length of 3.
class jsonweb.schema.validators.Number(**kw)

Validates something is a number

>>> Number().validate(1)
... 1
>>> Number().validate(1.1)
>>> 1.1
>>> Number().validate("foo")
Traceback (most recent call last):
    ...
ValidationError: Expected number got int instead.
class jsonweb.schema.validators.Integer(**kw)

Validates something in an integer

class jsonweb.schema.validators.Float(**kw)

Validates something is a float

class jsonweb.schema.validators.DateTime(format='', **kw)

Validates that something is a date/datetime string

>>> DateTime().validate("2010-01-02 12:30:00")
... datetime.datetime(2010, 1, 2, 12, 30)

>>> DateTime().validate("2010-01-02 12:300")
Traceback (most recent call last):
    ...
ValidationError: time data '2010-01-02 12:300' does not match format '%Y-%m-%d %H:%M:%S'

The default datetime format is %Y-%m-%d %H:%M:%S. You can specify your own

>>> DateTime("%m/%d/%Y").validate("01/02/2010")
... datetime.datetime(2010, 1, 2, 0, 0)    
class jsonweb.schema.validators.EnsureType(_type, type_name=None, **kw)

Validates something is a certian type

>>> class Person(object):
...     pass
>>> EnsureType(Person).validate(Person())
... <Person>
>>> EnsureType(Person).validate(10)
Traceback (most recent call last):
    ...
ValidationError: Expected Person got int instead.        
class jsonweb.schema.validators.List(validator, **kw)

Validates a list of things. The List constructor accepts a validator and each item in a the list will be validated against it

>>> List(Integer).validate([1,2,3,4])
... [1,2,3,4]

>>> List(Integer).validate(10)
...
ValidationError: Expected list got int instead.

Since ObjectSchema is also a validator we can do this

>>> class PersonSchema(ObjectSchema):
...     first_name = String()
...     last_name = String()
...
>>> List(PersonSchema).validate([
...     {"first_name": "bob", "last_name": "smith"},
...     {"first_name": "jane", "last_name": "smith"}
... ])