Search code examples
python-3.xpytestcerberus

Validating JSON Schema with Cerberus throws error when using correct data type


I am trying to validate a JSON schema. When specifying the correct data type date for released Cerberus throws an error.

def test_validate_books_schema():
    schema = {
            "url" : {'type': 'string'},
            "name" : {'type': 'string'},
            "isbn" : {'type': 'string'},
            "authors" : {'type': ['string','list']},
            "numberOfPages" : {'type': 'integer'},
            "publisher" : {'type': 'string'},
            "country" : {'type': 'string'},
            "mediaType" : {'type': 'string'},
            "released" : {'type': 'date'},
            "characters" : {'type': ['string','list']},
            "povCharacters" : {'type': ['string','list']}            
        }

    response = requests.get("https://www.anapioficeandfire.com/api/books/1")
    
    v = Validator(schema)
    validate_response = v.validate(response.json())
    assert_that(validate_response, description=v.errors).is_true()
./tests/books/test_books.py::test_validate_books_schema Failed: [undefined]AssertionError: [{'released': ['must be of date type']}] Expected <True>, but was not.
def test_validate_books_schema():
        schema = {
                "url" : {'type': 'string'},
                "name" : {'type': 'string'},
                "isbn" : {'type': 'string'},
                "authors" : {'type': ['string','list']},
                "numberOfPages" : {'type': 'integer'},
                "publisher" : {'type': 'string'},
                "country" : {'type': 'string'},
                "mediaType" : {'type': 'string'},
                "released" : {'type': 'date'},
                "characters" : {'type': ['string','list']},
                "povCharacters" : {'type': ['string','list']}
            }
    
        response = requests.get("https://www.anapioficeandfire.com/api/books/1")
    
        v = Validator(schema)
        validate_response = v.validate(response.json())
>       assert_that(validate_response, description=v.errors).is_true()
E       AssertionError: [{'released': ['must be of date type']}] Expected <True>, but was not.

tests\books\test_books.py:42: AssertionError

The documentation states that the data type for released is Date. When I specify string for released it works.


Solution

  • Change your code just slightly like so:

    from cerberus import Validator
    from assertpy import assert_that
    from datetime import datetime
    import requests
    
    def date_hook(json_dict):
        for (key, value) in json_dict.items():
            try:
                json_dict[key] = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S")
            except:
                pass
        return json_dict
    
    def test_validate_books_schema():
        schema = {
                "url" : {'type': 'string'},
                "name" : {'type': 'string'},
                "isbn" : {'type': 'string'},
                "authors" : {'type': ['string','list']},
                "numberOfPages" : {'type': 'integer'},
                "publisher" : {'type': 'string'},
                "country" : {'type': 'string'},
                "mediaType" : {'type': 'string'},
                "released" : {'type': 'date'},
                "characters" : {'type': ['string','list']},
                "povCharacters" : {'type': ['string','list']}            
            }
    
        response = requests.get("https://www.anapioficeandfire.com/api/books/1")
    
        v = Validator(schema)
        validate_response = v.validate(response.json(object_hook=date_hook))
        assert_that(validate_response, description=v.errors).is_true()
    
    test_validate_books_schema()
    print('Done')
    

    What we did here is add an object hook in response.json that'll call date_hook, which formats date/time appropriately (see this answer)

    Once you run your file, you should not get any error.