2121 Response ,
2222 json_response ,
2323)
24- from collections import defaultdict
24+ from collections import defaultdict , MutableMapping
2525from jsonschema import (
26- validate ,
2726 ValidationError ,
2827 FormatChecker ,
28+ Draft4Validator ,
29+ validators ,
2930)
30- from jsonschema .validators import validator_for
3131
3232
3333__all__ = (
@@ -54,12 +54,35 @@ def multi_dict_to_dict(mld: Mapping) -> Mapping:
5454 }
5555
5656
57- def validate_schema (obj : Mapping , schema : Mapping ):
58- validate (obj , schema , format_checker = FormatChecker ())
57+ def extend_with_default (validator_class ):
5958
59+ validate_properties = validator_class .VALIDATORS ["properties" ]
6060
61- def validate_multi_dict (obj , schema ):
62- validate (multi_dict_to_dict (obj ), schema , format_checker = FormatChecker ())
61+ def set_defaults (validator , properties , instance , schema ):
62+ if isinstance (instance , MutableMapping ):
63+ for prop , sub_schema in properties .items ():
64+ if "default" in sub_schema :
65+ instance .setdefault (prop , sub_schema ["default" ])
66+ for error in validate_properties (
67+ validator , properties , instance , schema ):
68+ yield error
69+
70+ return validators .extend (validator_class , {"properties" : set_defaults })
71+
72+
73+ json_schema_validator = extend_with_default (Draft4Validator )
74+
75+
76+ def validate_schema (obj : Mapping , schema : Mapping ) -> Mapping :
77+ json_schema_validator (schema , format_checker = FormatChecker ()).validate (obj )
78+ return obj
79+
80+
81+ def validate_multi_dict (obj , schema ) -> Mapping :
82+ _obj = multi_dict_to_dict (obj )
83+ json_schema_validator (
84+ schema , format_checker = FormatChecker ()).validate (_obj )
85+ return _obj
6386
6487
6588def validate_content_type (swagger : Mapping , content_type : str ):
@@ -73,34 +96,34 @@ async def validate_request(
7396 request : Request ,
7497 parameter_groups : Mapping ,
7598 swagger : Mapping ):
99+ res = {}
76100 validate_content_type (swagger , request .content_type )
77- for group_name , group_schemas in parameter_groups .items ():
101+ for group_name , group_schema in parameter_groups .items ():
78102 if group_name == 'header' :
79- headers = request .headers
80- for schema in group_schemas :
81- validate_multi_dict (headers , schema )
103+ res ['headers' ] = validate_multi_dict (request .headers , group_schema )
82104 if group_name == 'query' :
83- query = request .query
84- for schema in group_schemas :
85- validate_multi_dict (query , schema )
105+ res ['query' ] = validate_multi_dict (request .query , group_schema )
86106 if group_name == 'formData' :
87107 try :
88108 data = await request .post ()
89109 except ValueError :
90110 data = None
91- for schema in group_schemas :
92- validate_multi_dict (data , schema )
111+ res ['formData' ] = validate_multi_dict (data , group_schema )
93112 if group_name == 'body' :
94- try :
95- content = await request .json ()
96- except json .JSONDecodeError :
97- content = None
98- for schema in group_schemas :
99- validate_schema (content , schema )
113+ if request .content_type == 'application/json' :
114+ try :
115+ content = await request .json ()
116+ except json .JSONDecodeError :
117+ content = None
118+ elif request .content_type .startswith ('text' ):
119+ content = await request .text ()
120+ else :
121+ content = await request .read ()
122+ res ['body' ] = validate_schema (content , group_schema )
100123 if group_name == 'path' :
101124 params = dict (request .match_info )
102- for schema in group_schemas :
103- validate_schema ( params , schema )
125+ res [ 'path' ] = validate_schema ( params , group_schema )
126+ return res
104127
105128
106129def adjust_swagger_item_to_json_schemes (* schemes : Mapping ) -> Mapping :
@@ -124,7 +147,7 @@ def adjust_swagger_item_to_json_schemes(*schemes: Mapping) -> Mapping:
124147 required_fields .append (name )
125148 if required_fields :
126149 new_schema ['required' ] = required_fields
127- validator_for (new_schema ).check_schema (new_schema )
150+ validators . validator_for (new_schema ).check_schema (new_schema )
128151 return new_schema
129152
130153
@@ -139,21 +162,21 @@ def adjust_swagger_body_item_to_json_schema(schema: Mapping) -> Mapping:
139162 new_schema ,
140163 ]
141164 }
142- validator_for (new_schema ).check_schema (new_schema )
165+ validators . validator_for (new_schema ).check_schema (new_schema )
143166 return new_schema
144167
145168
146169def adjust_swagger_to_json_schema (parameter_groups : Iterable ) -> Mapping :
147- res = defaultdict ( list )
170+ res = {}
148171 for group_name , group_schemas in parameter_groups :
149172 if group_name in ('query' , 'header' , 'path' , 'formData' ):
150173 json_schema = adjust_swagger_item_to_json_schemes (* group_schemas )
151- res [group_name ]. append ( json_schema )
174+ res [group_name ] = json_schema
152175 else :
153176 # only one possible schema for in: body
154177 schema = list (group_schemas )[0 ]
155178 json_schema = adjust_swagger_body_item_to_json_schema (schema )
156- res [group_name ]. append ( json_schema )
179+ res [group_name ] = json_schema
157180 return res
158181
159182
@@ -179,7 +202,7 @@ def validation_exc_to_dict(exc, code=400):
179202 }
180203
181204
182- def dereference_schema (swagger : Mapping , schema : Any ) -> Any :
205+ def dereference_schema (swagger : Mapping , schema : Any , current_ref = None ) -> Any :
183206
184207 def get_ref (ref : str ):
185208 path = filter (None , ref .lstrip ('#' ).split ('/' ))
@@ -189,7 +212,14 @@ def get_ref(ref: str):
189212 res = {}
190213 for key , value in schema .items ():
191214 if key == '$ref' :
192- res .update (get_ref (value ))
215+ ref = value
216+ if current_ref is not None and ref == current_ref :
217+ raise ValidationError (
218+ 'Cycle swagger reference in schema: {}' .format (ref ))
219+ ref_data = get_ref (value )
220+ ref_data_resolved = dereference_schema (
221+ swagger , ref_data , current_ref = ref )
222+ res .update (ref_data_resolved )
193223 else :
194224 res [key ] = dereference_schema (swagger , value )
195225 return res
@@ -216,7 +246,9 @@ async def _wrapper(*args, **kwargs) -> Response:
216246 request = args [0 ].request \
217247 if isinstance (args [0 ], web .View ) else args [0 ]
218248 try :
219- await validate_request (request , parameter_groups , schema )
249+ validation = \
250+ await validate_request (request , parameter_groups , schema )
251+ request .validation = validation
220252 except ValidationError as exc :
221253 logger .exception (exc )
222254 exc_dict = validation_exc_to_dict (exc )
0 commit comments