Skip to content

Commit cb000f7

Browse files
committed
Initial schemas validation support
1 parent 42f3975 commit cb000f7

File tree

7 files changed

+1787
-2
lines changed

7 files changed

+1787
-2
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Current
88

99
- Fix missing changelog inprevious release
1010
- Ensure definitions with both `$ref` and description (or other property) output is valid (using `allOf`)
11+
- Added initial specifications schemas and validation support
1112

1213
0.12.0 (2018-09-27)
1314
-------------------

doc/api.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ Errors
7575
.. autoexception:: flask_restplus.mask.ParseError
7676

7777

78+
Schemas
79+
-------
80+
81+
.. automodule:: flask_restplus.schemas
82+
:members:
83+
84+
7885
Internals
7986
---------
8087

flask_restplus/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from flask.helpers import _endpoint_from_view_func
2020
from flask.signals import got_request_exception
2121

22-
from jsonschema import RefResolver
22+
from jsonschema import RefResolver, validate
2323

2424
from werkzeug import cached_property
2525
from werkzeug.datastructures import Headers

flask_restplus/schemas/__init__.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
This module give access to OpenAPI specifications schemas
4+
and allows to validate specs against them.
5+
6+
.. versionadded:: 0.12.1
7+
'''
8+
from __future__ import unicode_literals
9+
10+
import json
11+
import pkg_resources
12+
13+
from collections import Mapping
14+
15+
from jsonschema import Draft4Validator
16+
17+
from flask_restplus import errors
18+
19+
20+
class SchemaValidationError(errors.ValidationError):
21+
'''
22+
Raised when specification is not valid
23+
24+
.. versionadded:: 0.12.1
25+
'''
26+
def __init__(self, msg, errors=None):
27+
super(SchemaValidationError, self).__init__(msg)
28+
self.errors = errors
29+
30+
def __str__(self):
31+
msg = [self.msg]
32+
for error in sorted(self.errors, key=lambda e: e.path):
33+
path = '.'.join(error.path)
34+
msg.append('- {}: {}'.format(path, error.message))
35+
for suberror in sorted(error.context, key=lambda e: e.schema_path):
36+
path = '.'.join(suberror.schema_path)
37+
msg.append(' - {}: {}'.format(path, suberror.message))
38+
return '\n'.join(msg)
39+
40+
__unicode__ = __str__
41+
42+
43+
class LazySchema(Mapping):
44+
'''
45+
A thin wrapper around schema file lazy loading the data on first access
46+
47+
:param filename str: The package relative json schema filename
48+
:param validator: The jsonschema validator class version
49+
50+
.. versionadded:: 0.12.1
51+
'''
52+
def __init__(self, filename, validator=Draft4Validator):
53+
super(LazySchema, self).__init__()
54+
self.filename = filename
55+
self._schema = None
56+
self._validator = validator
57+
58+
def _load(self):
59+
if not self._schema:
60+
data = pkg_resources.resource_string(__name__, self.filename)
61+
self._schema = json.loads(data)
62+
63+
def __getitem__(self, key):
64+
self._load()
65+
return self._schema.__getitem__(key)
66+
67+
def __iter__(self):
68+
self._load()
69+
return self._schema.__iter__()
70+
71+
def __len__(self):
72+
self._load()
73+
return self._schema.__len__()
74+
75+
@property
76+
def validator(self):
77+
'''The jsonschema validator to validate against'''
78+
return self._validator(self)
79+
80+
81+
#: OpenAPI 2.0 specification schema
82+
OAS_20 = LazySchema('oas-2.0.json')
83+
84+
#: Map supported OpenAPI versions to their JSON schema
85+
VERSIONS = {
86+
'2.0': OAS_20,
87+
}
88+
89+
90+
def validate(data):
91+
'''
92+
Validate an OpenAPI specification.
93+
94+
Supported OpenAPI versions: 2.0
95+
96+
:param data dict: The specification to validate
97+
:returns boolean: True if the specification is valid
98+
:raises SchemaValidationError: when the specification is invalid
99+
:raises flask_restplus.errors.SpecsError: when it's not possible to determinate
100+
the schema to validate against
101+
102+
.. versionadded:: 0.12.1
103+
'''
104+
if 'swagger' not in data:
105+
raise errors.SpecsError('Unable to determinate OpenAPI schema version')
106+
107+
version = data['swagger']
108+
if version not in VERSIONS:
109+
raise errors.SpecsError('Unknown OpenAPI schema version "{}"'.format(version))
110+
111+
validator = VERSIONS[version].validator
112+
113+
validation_errors = list(validator.iter_errors(data))
114+
if validation_errors:
115+
raise SchemaValidationError('OpenAPI {} validation failed'.format(version),
116+
errors=validation_errors)
117+
return True

0 commit comments

Comments
 (0)