Python flask json schema validation

Question:

I am using the flask framework in my new project. It would get JSON data from the post and send a JSON response. So, I need to validate my JSON request.

I have seen couple of libraries. But those libraries are not working as expected. Finally, I have decided to go with a flask-jsonschema-validator. It is working fine with a single JSON object. If the request object has a nested object, it is not working.

For example:

from flask_jsonschema_validator import JSONSchemaValidator
JSONSchemaValidator(app=app, root="schemas")

This is my initialization of the validator:

# If any error occurred in the request.
@app.errorhandler(jsonschema.ValidationError)
def json_validation_error(e):
    return json_response("error", str(e), {})

This is my error handler

@app.validate('model', 'save')
def save_model():

This is my implementation:

{
  "save": {
    "type": "object",
    "properties": {
      "workspace": {"type": "object"},
      "name": {"type": "string"},
      "description": {"type": "string"},
      "uri": {"type": "string"},
      "type": {
         "name": {"type": "string"},
      }
    },
    "required": [ "workspace", "name", "description", "uri", "type"]
  }
}

This is my model.json file. It is validating the request except for the "type". How to apply validation for JSON request with nested object.

Asked By: az rnd

||

Answers:

flask-expects-json package checks variables types on nested objects.

It work as a decorator on your route.

SCHEMA = {
    "type": "object",
    "properties": {
      "workspace": {"type": "object"},
      "name": {"type": "string"},
      "description": {"type": "string"},
      "uri": {"type": "string"},
      "type": {
         "type": "object",
         "properties": {
              "name": {"type": "string"},
         }
      }
    },
    "required": ["workspace", "name", "description", "uri", "type"]
}

@expects_json(SCHEMA)
def my_route(self, **kwargs):
    pass
Answered By: AlexisG

If the validation of complex nested objects, I would recommend an alternative tool to JSONSchema. I can replicate your schema validation in GoodJSON like below. As you can see, formulating a validation schema is just composing a bunch of self-contained validator functions that can be applied to objects, lists and primitive values.

from goodjson.validators import is_dict, is_string, is_uri, foreach_key


validate_fun = foreach_key(
    save=[foreach_key(
        workspace=[is_dict],
        name=[is_string],
        description=[is_string],
        uri=[is_uri],
        type=[foreach_key(
            name=[is_string]
        )]
    )]
)

validate_fun(YOUR_JSON_DATA_OBJECT)

Disclaimer: I am the author of GoodJSON.

Answered By: Namoshizun

Here’s how I do it using dataclasses, it requires a library called dataclass_utils, which can be installed using pip install dataclass_utils

from dataclasses import dataclass
from functools import wraps
from typing import Any

from dataclass_utils.type_checker import check_dataclass
from flask import Flask

app = Flask(__name__)


@dataclass
class Schema:
    username: str
    some_field: str
    some_number: int


def validate_schema(the_dataclass: Any):
    def _validate_schema(org_func):
        @wraps(org_func)
        def wrapper(*args, **kwargs):
            from flask import request
            td = the_dataclass(**request.json)
            err = check_dataclass(td, type(td))
            if err is not None:
                return "schema invalid", 400
            return org_func(*args, **kwargs)
        return wrapper
    return _validate_schema


@app.route("/someApiEndpoint", methods=["POST"])
@validate_schema(the_dataclass=Schema)
def someApiEndpoint():
    return "yay the schema is valid", 200


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080, debug=True)
Answered By: Chandan
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.