diff --git a/README.md b/README.md new file mode 100644 index 0000000..6b80c7a --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# `flask_restful_jsonschema` + +Add the `@validate_json` decorator and schema class constant to +`flask_restful.Resource` methods (post, get, etc.) in order to validate +requests meet the `jsonschema`. + + +```python +from flask_restful_jsonschema import validate_json + + +class Users(flask_restful.Resource): + SCHEMA_POST = { + "type": "object", + "properties": { + "email": {"type": "string"}, + "password": {"type": "string"}, + }, + "required": ["email", "password"], + } + SCHEMA_PUT = { + "type": "object", + "properties": { + "email": {"type": "string"}, + "password": {"type": "string"}, + }, + } + SCHEMA_GET = { + "type": "object", + "properties": { + "email": {"type": "string"}, + }, + "required": ["email"], + } + + @validate_json + def post(self, json_request): + pass + + @validate_json + def put(self, json_request): + pass + + @validate_json + def get(self, json_request): + pass +``` diff --git a/flask_restful_jsonschema.py b/flask_restful_jsonschema.py new file mode 100644 index 0000000..0c7807a --- /dev/null +++ b/flask_restful_jsonschema.py @@ -0,0 +1,46 @@ +import jsonschema +import flask +import flask_restful + + +def get_valid_json_or_abort(schema): + """Either return the request's JSON, which + matches the supplied JSON `schema`. + + Arguments: + schema (dict): See jsonschema Python package. + + Aborts: + 400: The request does not adhere to the schema. + + Returns: + JSON: JSON that fits the supplied `schema`. + + """ + + json_request = flask.request.get_json(force=True) + + try: + jsonschema.validate(json_request, schema) + except jsonschema.ValidationError as e: + flask_restful.abort(400, message=e.message) + else: + return json_request + + +def validate_json(func): + """Decorator specifically for wrapping flask_restful + Resource method... methods (get/post/put, etc.). + + """ + + # get the function name because we're going to + # see if we need SCHEMA_POST, SCHEMA_GET, etc. + function_name = func.__name__.upper() + + def wrapped_func(self, *args, **kwargs): + respective_schema = getattr(self, 'SCHEMA_' + function_name) + json_request = get_valid_json_or_abort(respective_schema) + return func(self, json_request, *args, **kwargs) + + return wrapped_func diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ffabd98 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +jsonschema +flask +flask_restful