1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
# coding: utf-8
import inspect
from flask.views import MethodView
import flasgger
try:
from marshmallow import Schema, fields
from apispec.ext.marshmallow import openapi
from apispec import APISpec as BaseAPISpec
# Note that openapi_converter is initialized with trivial
# schema_name_resolver. Resolving circular reference is not
# supported for now. See issue #314 .
# Also see: https://github.com/marshmallow-code/apispec/pull/447
openapi_converter = openapi.OpenAPIConverter(
openapi_version='2.0',
schema_name_resolver=lambda schema: None,
spec=None
)
schema2jsonschema = openapi_converter.schema2jsonschema
schema2parameters = openapi_converter.schema2parameters
except ImportError:
Schema = None
fields = None
schema2jsonschema = lambda schema: {} # noqa
schema2parameters = lambda schema: [] # noqa
BaseAPISpec = object
class APISpec(BaseAPISpec):
"""
Wrapper around APISpec to add `to_flasgger` method
"""
def to_flasgger(self, app=None, definitions=None, paths=None):
"""
Converts APISpec dict to flasgger suitable dict
also adds definitions and paths (optional)
"""
if Schema is None:
raise RuntimeError('Please install marshmallow and apispec')
return flasgger.utils.apispec_to_template(
app,
self,
definitions=definitions,
paths=paths
)
class SwaggerView(MethodView):
"""
A Swagger view
"""
parameters = []
responses = {}
definitions = {}
tags = []
consumes = ['application/json']
produces = ['application/json']
schemes = []
security = []
deprecated = False
operationId = None
externalDocs = {}
summary = None
description = None
validation = False
validation_function = None
validation_error_handler = None
def dispatch_request(self, *args, **kwargs):
"""
If validation=True perform validation
"""
if self.validation:
specs = {}
attrs = flasgger.constants.OPTIONAL_FIELDS + [
'parameters', 'definitions', 'responses',
'summary', 'description'
]
for attr in attrs:
specs[attr] = getattr(self, attr)
definitions = {}
specs.update(convert_schemas(specs, definitions))
specs['definitions'] = definitions
flasgger.utils.validate(
specs=specs, validation_function=self.validation_function,
validation_error_handler=self.validation_error_handler
)
return super(SwaggerView, self).dispatch_request(*args, **kwargs)
def convert_schemas(d, definitions=None):
"""
Convert Marshmallow schemas to dict definitions
Also updates the optional definitions argument with any definitions
entries contained within the schema.
"""
if definitions is None:
definitions = {}
definitions.update(d.get('definitions', {}))
new = {}
for k, v in d.items():
if isinstance(v, dict):
v = convert_schemas(v, definitions)
if isinstance(v, (list, tuple)):
new_v = []
for item in v:
if isinstance(item, dict):
new_v.append(convert_schemas(item, definitions))
else:
new_v.append(item)
v = new_v
if inspect.isclass(v) and issubclass(v, Schema):
if Schema is None:
raise RuntimeError('Please install marshmallow and apispec')
definitions[v.__name__] = schema2jsonschema(v)
ref = {
"$ref": "#/definitions/{0}".format(v.__name__)
}
if k == 'parameters':
new[k] = schema2parameters(v)
new[k][0]['schema'] = ref
else:
new[k] = ref
else:
new[k] = v
# This key is not permitted anywhere except the very top level.
if 'definitions' in new:
del new['definitions']
return new
|