Python json schema that extracts parameters
<p>I need to parse requests to a single url that are coming in JSON, but in several different formats. For example, some have timestamp noted as <code>timestamp</code> attr, others as <code>unixtime</code> etc. So i want to create json schemas for all types of requests that not only validate incoming JSONs but also extract their parameters from specified places. Is there a library that can do that?</p>

<p>Example:</p>

<p>If I could define a schema that would look something like this</p>

<pre><code>schema = {
    "type" : "object",
    "properties" : {
        "price" : {
            "type" : "number",
            "mapped_name": "product_price"
        },
        "name" : {
            "type" : "string",
            "mapped_name": "product_name"

        },
        "added_at":{
            "type" : "int",
            "mapped_name": "timestamp"

        },
    },
}
</code></pre>

<p>and then apply it to a dict </p>

<pre><code>request = {
    "name" : "Eggs",
    "price" : 34.99,
    'added_at': 1234567
}
</code></pre>

<p>by some magical function</p>

<pre><code>params = validate_and_extract(request, schema)
</code></pre>

<p>I want <code>params</code> to have mapped values there:</p>

<pre><code>{"mapped_name": "Eggs", "product_price": 34.99, "timestamp": 1234567}
</code></pre>

<p>so this is a module I'm looking for. And it should support nested dicts in <code>request</code>, not just flat dicts.</p>

<p>The following code may help. It supports nested dict as well.</p>

<pre><code>import json


def valid_type(type_name, obj):
    if type_name == "number":
        return isinstance(obj, int) or isinstance(obj, float)

    if type_name == "int":
        return isinstance(obj, int)

    if type_name == "float":
        return isinstance(obj, float)

    if type_name == "string":
        return isinstance(obj, str)


def validate_and_extract(request, schema):
    ''' Validate request (dict) against the schema (dict).

        Validation is limited to naming and type information.
        No check is done to ensure all elements in schema
        are present in the request. This could be enhanced by
        specifying mandatory/optional/conditional information
        within the schema and subsequently checking for that.
    '''
    out = {}

    for k, v in request.items():
        if k not in schema['properties'].keys():
            print("Key '{}' not in schema ... skipping.".format(k))
            continue

        if schema['properties'][k]['type'] == 'object':
            v = validate_and_extract(v, schema['properties'][k])

        elif not valid_type(schema['properties'][k]['type'], v):
            print("Wrong type for '{}' ... skipping.".format(k))
            continue

        out[schema['properties'][k]['mapped_name']] = v

    return out


# Sample Data 1
schema1 = {
    "type" : "object",
    "properties" : {
        "price" : {
            "type" : "number",
            "mapped_name": "product_price"
        },
        "name" : {
            "type" : "string",
            "mapped_name": "product_name"

        },
        "added_at":{
            "type" : "int",
            "mapped_name": "timestamp"

        },
    },
}
request1 = {
    "name" : "Eggs",
    "price" : 34.99,
    'added_at': 1234567
}

# Sample Data 2: containing nested dict
schema2 = {
    "type" : "object",
    "properties" : {
        "price" : {
            "type" : "number",
            "mapped_name": "product_price"
        },
        "name" : {
            "type" : "string",
            "mapped_name": "product_name"
        },
        "added_at":{
            "type" : "int",
            "mapped_name": "timestamp"
        },
        "discount":{
            "type" : "object",
            "mapped_name": "offer",
            "properties" : {
                "percent": {
                    "type" : "int",
                    "mapped_name": "percentage"
                },
                "last_date": {
                    "type" : "string",
                    "mapped_name": "end_date"
                },
            }
        },
    },
}
request2 = {
    "name" : "Eggs",
    "price" : 34.99,
    'added_at': 1234567,
    'discount' : {
        'percent' : 40,
        'last_date' : '2016-09-25'
    }
}


params = validate_and_extract(request1, schema1)
print(params)

params = validate_and_extract(request2, schema2)
print(params)
</code></pre>

<p>Output from running this:</p>

<pre><code>{'timestamp': 1234567, 'product_name': 'Eggs', 'product_price': 34.99}
{'offer': {'percentage': 40, 'end_date': '2016-09-25'}, 'timestamp': 1234567, 'product_name': 'Eggs', 'product_price': 34.99}
</code></pre>

python json