def get_specification(self): spec = APISpec( title=self.__class__.__name__, version='1.0.0', plugins=( 'apispec.ext.flask', 'apispec.ext.marshmallow', ), ) class PetSchema(Schema): id = fields.Int() name = fields.Str() app = Flask(__name__) @app.route('/random') def random_pet(): """A cute furry animal endpoint. --- get: description: Get a random pet responses: 200: description: A pet to be returned schema: PetSchema """ return jsonify({}) # Register entities and paths spec.definition('Pet', schema=PetSchema) with app.test_request_context(): spec.add_path(view=random_pet) return json.dumps(spec.to_dict(), indent=4)
def test_plugin_response_helper_is_used(self, spec): spec = APISpec( title='Swagger Petstore', version='1.0.0', plugins=(self.TestPlugin(), ), ) spec.add_path( '/path_3', operations={'delete': { 'responses': { '204': { 'content': {} } } }}) assert len(spec._paths) == 1 assert spec._paths['/path_3'] == { 'delete': { 'responses': { '204': { 'content': {}, 'description': 'Clever description', } } } }
def test_resolve_schema_dict_auto_reference_in_list(self, schema): def resolver(schema): return schema.__name__ spec = APISpec( title='Test auto-reference', version='0.1', openapi_version='2.0', plugins=(MarshmallowPlugin(schema_name_resolver=resolver, ), ), ) assert {} == get_definitions(spec) spec.definition('analysis', schema=schema) spec.add_path( '/test', operations={ 'get': { 'responses': { '200': { 'schema': { '$ref': '#/definitions/analysis', }, }, }, }, }, ) definitions = get_definitions(spec) assert 3 == len(definitions) assert 'analysis' in definitions assert 'SampleSchema' in definitions assert 'RunSchema' in definitions
def register_spec(app): """ Creates an API spec and puts it on the app """ from apispec import APISpec spec = APISpec( title='Kids First Data Service', version=_get_version(), plugins=[ 'apispec.ext.flask', 'apispec.ext.marshmallow', ], ) from dataservice.api import status_view, views from dataservice.api.common.schemas import StatusSchema spec.definition('Status', schema=StatusSchema) from dataservice.api.common.views import CRUDView CRUDView.register_spec(spec) with app.test_request_context(): spec.add_path(view=status_view) for view in views: spec.add_path(view=view) app.spec = spec
def test_resolve_schema_dict_auto_reference_in_list(self, schema): def resolver(schema): return schema.__name__ spec = APISpec( title='Test auto-reference', version='2.0', description='Test auto-reference', plugins=('apispec.ext.marshmallow', ), schema_name_resolver=resolver, ) assert {} == spec._definitions spec.definition('analysis', schema=schema) spec.add_path('/test', operations={ 'get': { 'responses': { '200': { 'schema': { '$ref': '#/definitions/analysis' } } } } }) assert 3 == len(spec._definitions) assert 'analysis' in spec._definitions assert 'SampleSchema' in spec._definitions assert 'RunSchema' in spec._definitions
def generate_swagger( app: web.Application, title=DEFAULT_TITLE, version=DEFAULT_VERSION, host=DEFAULT_HOST, schemes=DEFAULT_SCHEMES, definitions_path=DEFAULT_DEFINITIONS_PATH, **options ): if host is not None: options["host"] = host if schemes is not None: options["schemes"] = schemes spec = APISpec( title=title, version=version, plugins=("apispec.ext.marshmallow",), **options ) if definitions_path is not None: definitions = importlib.import_module(definitions_path) for name, schema in definitions.__dict__.items(): # type: str, Schema if name.endswith("Schema") and len(name) > len("Schema"): spec.definition(name, schema=schema) resources = app.router._resources for resource in resources: url = resource.canonical name = resource.name for route in resource._routes: method = route.method if method == "HEAD": continue handler = route._handler try: handler_spec = handler.swagger_spec except AttributeError: handler_spec = {} if "excluded" in handler_spec: continue try: handler_spec["summary"] = get_summary(handler.__doc__) handler_spec["description"] = handler.__doc__ except KeyError: pass parameters = get_parameters(url, handler, spec) if parameters: handler_spec["parameters"] = parameters handler_spec["operationId"] = name spec.add_path(url, operations={method.lower(): handler_spec}) return spec.to_dict()
def test_definition_autogeneration(app, routes): spec = APISpec( title='test api', version='0.1.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec')) spec.add_path(view=routes['fooList']) assert 'FooSchema' in spec.to_dict()['definitions']
def test_plugin_path_helper_is_used(self): spec = APISpec( title='Swagger Petstore', version='1.0.0', plugins=(self.TestPlugin(), ), ) spec.add_path('/path_1') assert len(spec._paths) == 1 assert spec._paths['/path_1_modified'] == {'get': {'responses': {'200': {}}}}
def test_tagging(app, routes): spec = APISpec( title='test api', version='0.1.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec')) spec.add_path(view=routes['fooList']) assert 'FooSchema' in spec.to_dict()['paths']['/foos']['get']['tags']
def test_plugin_operation_helper_is_used(self): spec = APISpec( title='Swagger Petstore', version='1.0.0', plugins=(self.TestPlugin(), ), ) spec.add_path('/path_2', operations={'post': {'responses': {'200': {}}}}) assert len(spec._paths) == 1 assert spec._paths['/path_2'] == {'post': {'responses': {'201': {}}}}
def build_openapi_spec(publish): """Creates an OpenAPI definition of Flask application, check conformity of generated definition against OpenAPI 2.0 specification and writes it into a file.""" package = __title__ desc = __api_description__ ver = __version__ # Create OpenAPI specification object spec = APISpec(title=package, version=ver, info=dict(description=desc), plugins=('apispec.ext.flask', 'apispec.ext.marshmallow')) # Add marshmallow schemas to the specification here # spec.definition('Example', schema=Example_schema) # Collect OpenAPI docstrings from Flask endpoints for key in current_app.view_functions: if key != 'static' and key != 'get_openapi_spec': spec.add_path(view=current_app.view_functions[key]) spec_json = json.dumps(spec.to_dict(), indent=2, separators=(',', ': '), sort_keys=True) # Output spec to JSON file with click.open_file(__output_path__, mode='w+', encoding=None, errors='strict', lazy=False, atomic=False) as output_file: output_file.write(spec_json) click.echo( click.style('OpenAPI specification written to {}'.format( output_file.name), fg='green')) # Check that generated spec passes validation. Done after writing to file # in order to give user easy way to access the possible erroneous spec. with open(os.path.join(os.getcwd(), __output_path__)) as output_file: validate_json(json.load(output_file), 'schemas/v2.0/schema.json') click.echo( click.style('OpenAPI specification validated successfully', fg='green')) if publish: copy_openapi_specs(__output_path__, 'reana-workflow-controller') return spec.to_dict()
def test_tagging(views): spec = APISpec( title='test api', version='0.1.0', plugins=(FlaskRestyPlugin(), ), ) spec.add_path(view=views['foo_list']) assert 'FooSchema' in spec.to_dict()['paths']['/foos']['get']['tags']
def test_definition_autogeneration(views): spec = APISpec( title='test api', version='0.1.0', plugins=(FlaskRestyPlugin(), ), ) spec.add_path(view=views['foo_list']) assert 'FooSchema' in spec.to_dict()['definitions']
def test_tagging(views): spec = APISpec( title='test api', version='0.1.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec'), ) spec.add_path(view=views['foo_list']) assert 'FooSchema' in spec.to_dict()['paths']['/foos']['get']['tags']
def test_definition_autogeneration(views): spec = APISpec( title='test api', version='0.1.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec'), ) spec.add_path(view=views['foo_list']) assert 'FooSchema' in spec.to_dict()['definitions']
def test_swagger_tools_validate(): spec = APISpec( title='Pets', version='0.1', plugins=['apispec.ext.marshmallow'], ) spec.definition('Category', schema=CategorySchema) spec.definition('Pet', schema=PetSchema) spec.add_path( view=None, path='/category/{category_id}', operations={ 'get': { 'parameters': [ {'name': 'q', 'in': 'query', 'type': 'string'}, {'name': 'category_id', 'in': 'path', 'required': True, 'type': 'string'}, field2parameter( field=fields.List( fields.Str(), validate=validate.OneOf(['freddie', 'roger']), location='querystring', ), name='body', use_refs=False, ), ] + swagger.schema2parameters(PageSchema, default_in='query'), 'responses': { 200: { 'schema': PetSchema, 'description': 'A pet', }, }, }, 'post': { 'parameters': ( [{'name': 'category_id', 'in': 'path', 'required': True, 'type': 'string'}] + swagger.schema2parameters(CategorySchema, spec=spec, default_in='body') ), 'responses': { 201: { 'schema': PetSchema, 'description': 'A pet', }, }, } }, ) try: utils.validate_swagger(spec) except exceptions.SwaggerError as error: pytest.fail(str(error))
def swagger_json(hug_api): spec = APISpec(title=settings.TITLE, description=settings.DESCRIPTION, version=settings.VERSION, plugins=('apispec.ext.marshmallow', ), schemes=settings.SCHEMES, host=settings.HOST) if settings.DEFINITIONS_PATH is not None: definitions = importlib.import_module(settings.DEFINITIONS_PATH) for name, schema in definitions.__dict__.items(): # type: str, Schema if name.endswith('Schema') and len(name) > len('Schema'): spec.definition(name, schema=schema) routes = hug_api.http.routes[''] for url, route in routes.items(): for method, versioned_interfaces in route.items(): for versions, interface in versioned_interfaces.items(): methods_data = {} documentation = interface.documentation() methods_data['content_type'] = documentation['outputs'][ 'content_type'] try: methods_data['summary'] = get_summary( documentation['usage']) methods_data['description'] = documentation['usage'] except KeyError: pass parameters = get_parameters(url, interface, spec) if parameters: methods_data['parameters'] = parameters responses = get_operation(interface, spec, settings.USE_DEFAULT_RESPONSE) if responses: methods_data['responses'] = responses if not isinstance(versions, collections.Iterable): versions = [versions] for version in versions: versioned_url = '/v{}{}'.format(version, url) if version else url spec.add_path(versioned_url, operations={method.lower(): methods_data}) return spec.to_dict()
def spec(app, schemas, routes): spec = APISpec( title='test api', version='0.1.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec')) spec.definition('Foo', schema=schemas['foo']) spec.add_path(view=routes['fooList']) spec.add_path(view=routes['foo']) spec.add_path(view=routes['bar']) return spec.to_dict()
def test_resolve_schema_dict_auto_reference_return_none( self, schema, deprecated_interface): # this resolver return None def resolver(schema): return None if deprecated_interface: spec = APISpec( title='Test auto-reference', version='0.1', description='Test auto-reference', plugins=('apispec.ext.marshmallow', ), schema_name_resolver=resolver, ) else: spec = APISpec( title='Test auto-reference', version='0.1', description='Test auto-reference', plugins=(MarshmallowPlugin(schema_name_resolver=resolver, ), ), ) assert {} == spec._definitions spec.definition('analysis', schema=schema) spec.add_path( '/test', operations={ 'get': { 'responses': { '200': { 'schema': { '$ref': '#/definitions/analysis', }, }, }, }, }, ) # Other shemas not yet referenced assert 1 == len(spec._definitions) spec_dict = spec.to_dict() assert spec_dict.get('definitions') assert 'analysis' in spec_dict['definitions'] # Inspect/Read objects will not auto reference because resolver func # return None json.dumps(spec_dict) # Other shema still not referenced assert 1 == len(spec._definitions)
def spec(schemas, views): spec = APISpec( title='test api', version='0.1.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec'), ) spec.definition('Foo', schema=schemas['foo']) spec.add_path(view=views['foo_list']) spec.add_path(view=views['foo']) spec.add_path(view=views['bar']) return spec.to_dict()
def get_specification(self): spec = APISpec( title=self.__class__.__name__, version='1.0.0', plugins=( 'apispec.ext.flask', 'apispec.ext.marshmallow', ), ) class PetParameter(Schema): pet_id = fields.Int() class PetSchema(Schema): id = fields.Int() name = fields.Str() app = Flask(__name__) @app.route('/pets/<int:pet_id>') def get_pet(pet_id): """A cute furry animal endpoint. --- get: description: Get a random pet parameters: - in: path schema: PetParameter responses: 200: description: A pet to be returned schema: PetSchema """ return jsonify({}) # Register entities and paths spec.definition('Pet', schema=PetSchema) spec.definition('PetParameter', schema=PetParameter, required=True) with app.test_request_context(): spec.add_path(view=get_pet) specification_as_string = json.dumps(spec.to_dict(), indent=4) # Kludge! I was unable to do this via `apispec` specification_as_string = specification_as_string.replace('"required": false,', '"required": true,') return specification_as_string
def get_specification(self): spec = APISpec( title=self.__class__.__name__, version='1.0.0', plugins=( 'apispec.ext.flask', 'apispec.ext.marshmallow', ), ) class PetParameter(Schema): pet_id = fields.Int() class PetSchema(Schema): id = fields.Int() name = fields.Str() app = Flask(__name__) @app.route('/pets/<int:pet_id>') def get_pet(pet_id): """A cute furry animal endpoint. --- get: description: Get a random pet parameters: - in: path schema: PetParameter responses: 200: description: A pet to be returned schema: PetSchema """ return jsonify({}) # Register entities and paths spec.definition('Pet', schema=PetSchema) spec.definition('PetParameter', schema=PetParameter, required=True) with app.test_request_context(): spec.add_path(view=get_pet) specification_as_string = json.dumps(spec.to_dict(), indent=4) # Kludge! I was unable to do this via `apispec` specification_as_string = specification_as_string.replace( '"required": false,', '"required": true,') return specification_as_string
def test_resolve_schema_dict_auto_reference_return_none(self, schema): # this resolver return None def resolver(schema): return None def class_resolver(spec, schema): if isinstance(schema, type): return schema else: return type(schema) spec = APISpec( title='Test auto-reference', version='2.0', description='Test auto-reference', plugins=('apispec.ext.marshmallow', ), schema_name_resolver=resolver, schema_class_resolver=class_resolver, auto_referencing=True, ) assert {} == spec._definitions spec.definition('analysis', schema=schema) spec.add_path('/test', operations={ 'get': { 'responses': { '200': { 'schema': { '$ref': '#/definitions/analysis' } } } } }) # Other shemas not yet referenced assert 1 == len(spec._definitions) spec_dict = spec.to_dict() assert spec_dict.get('definitions') assert 'analysis' in spec_dict['definitions'] # Inspect/Read objects will not auto reference because resolver func # return None json.dumps(spec_dict) # Other shema still not referenced assert 1 == len(spec._definitions)
def check_web_framework_and_marshmallow_plugin(web_framework_plugin, **kwargs_for_add_path): """Check schemas passed in web framework view function docstring are parsed by MarshmallowPlugin""" spec = APISpec( title='Swagger Petstore', version='1.0.0', plugins=[web_framework_plugin(), MarshmallowPlugin()], openapi_version='2.0', ) spec.add_path(**kwargs_for_add_path) expected = { 'type': 'object', 'properties': { 'id': {'type': 'integer', 'format': 'int32', 'description': 'Pet id', 'readOnly': True}, 'name': {'type': 'string', 'description': 'Pet name'}, }, 'required': ['name'], } assert spec.to_dict()['paths']['/hello']['get']['responses'][200]['schema'] == expected
def _apispec(self): spec = APISpec( title=self.title, version=self.version, openapi_version=self.openapi_version, plugins=[MarshmallowPlugin()], ) for route in self.routes: if self.routes[route].description: operations = yaml_utils.load_operations_from_docstring( self.routes[route].description) spec.add_path(path=route, operations=operations) for name, schema in self.schemas.items(): spec.definition(name, schema=schema) return spec
def _load_swagger(url_specs, title=None): global api_spec api_spec = APISpec(title=title, version='1.0', plugins=('apispec.ext.marshmallow', 'apispec.ext.tornado')) # Schemas from Marshmallow api_spec.definition('Parameter', schema=ParameterSchema) api_spec.definition('Command', schema=CommandSchema) api_spec.definition('Instance', schema=InstanceSchema) api_spec.definition('Request', schema=RequestSchema) api_spec.definition('System', schema=SystemSchema) api_spec.definition('LoggingConfig', schema=LoggingConfigSchema) api_spec.definition('Event', schema=EventSchema) api_spec.definition('User', schema=PrincipalSchema) api_spec.definition('Role', schema=RoleSchema) api_spec.definition('Queue', schema=QueueSchema) api_spec.definition('RefreshToken', schema=RefreshTokenSchema) api_spec.definition('_patch', schema=PatchSchema) api_spec.definition('Patch', properties={"operations": { "type": "array", "items": {"$ref": "#/definitions/_patch"}} }) api_spec.definition('DateTrigger', schema=DateTriggerSchema) api_spec.definition('CronTrigger', schema=CronTriggerSchema) api_spec.definition('IntervalTrigger', schema=IntervalTriggerSchema) api_spec.definition('Job', schema=JobSchema) trigger_properties = { 'allOf': [ {'$ref': '#/definitions/CronTrigger'}, {'$ref': '#/definitions/DateTrigger'}, {'$ref': '#/definitions/IntervalTrigger'}, ], } api_spec._definitions['Job']['properties']['trigger'] = trigger_properties error = {'message': {'type': 'string'}} api_spec.definition('400Error', properties=error, description='Parameter validation error') api_spec.definition('404Error', properties=error, description='Resource does not exist') api_spec.definition('409Error', properties=error, description='Resource already exists') api_spec.definition('50xError', properties=error, description='Server exception') # Finally, add documentation for all our published paths for url_spec in url_specs: api_spec.add_path(urlspec=url_spec)
def test_resolve_schema_dict_auto_reference(self, schema, deprecated_interface): def resolver(schema): return schema.__name__ if deprecated_interface: spec = APISpec( title='Test auto-reference', version='0.1', description='Test auto-reference', plugins=('apispec.ext.marshmallow', ), schema_name_resolver=resolver, ) else: spec = APISpec( title='Test auto-reference', version='0.1', description='Test auto-reference', plugins=(MarshmallowPlugin(schema_name_resolver=resolver), ), ) assert {} == spec._definitions spec.definition('analysis', schema=schema) spec.add_path( '/test', operations={ 'get': { 'responses': { '200': { 'schema': { '$ref': '#/definitions/analysis', }, }, }, }, }, ) assert 3 == len(spec._definitions) assert 'analysis' in spec._definitions assert 'SampleSchema' in spec._definitions assert 'RunSchema' in spec._definitions
class AiohttpApiSpec: def __init__(self, url='/api/docs/api-docs', **kwargs): self.spec = APISpec(**kwargs) if 'apispec.ext.marshmallow' not in self.spec.plugins: self.spec.setup_plugin('apispec.ext.marshmallow') self.url = url def swagger_dict(self): return self.spec.to_dict() def register(self, app: web.Application): for route in app.router.routes(): view = route.handler method = route.method.lower() if hasattr(view, '__apispec__') and view.__apispec__['docked'].get( method) is not True: url_path = get_path(route) if url_path: if not view.__apispec__['docked'].get('parameters'): view.__apispec__['parameters'].extend({ "in": "path", "name": path_key, "required": True, "type": "string" } for path_key in get_path_keys(url_path) if path_key) view.__apispec__['docked']['parameters'] = True self._update_paths(view.__apispec__, method, url_path) view.__apispec__['docked'][method] = True app['swagger_dict'] = self.spec.to_dict() def swagger_handler(request): return web.json_response(request.app['swagger_dict']) app.router.add_routes([web.get(self.url, swagger_handler)]) def _update_paths(self, data: dict, method, url_path): operations = copy.deepcopy(data) operations.pop('docked', None) if method in PATHS: self.spec.add_path( Path(path=url_path, operations={method: operations}))
def build_openapi_spec(): """Create OpenAPI definition.""" spec = APISpec(title='reana-job-controller', version='0.4.0', info=dict(description='REANA Job Controller API'), plugins=[ 'apispec.ext.flask', 'apispec.ext.marshmallow', ]) # Add marshmallow models to specification spec.definition('Job', schema=Job) spec.definition('JobRequest', schema=JobRequest) # Collect OpenAPI docstrings from Flask endpoints for key in current_app.view_functions: if key != 'static' and key != 'get_openapi_spec': spec.add_path(view=current_app.view_functions[key]) return spec.to_dict()
def generate_specs(module_name): module = import_service_module(module_name) service_name = ''.split('.')[-1] ctx = module.app.test_request_context() ctx.push() spec = APISpec( title=service_name, version='1.0.0', plugins=('apispec.ext.marshmallow', 'flask_resty.spec')) schemas = get_subclasses(module.schemas, Schema) for schema in schemas: spec.definition(prettify_schema_name(schema), schema=schema) for view in get_subclasses(module.views, ApiView): try: spec.add_path(view=view, tag=True) except KeyError: pass # means that the view is not registered. move along return json.dumps(spec.to_dict(), indent=2)
def generate_specs(module_name, **options): module = import_service_module(module_name) service_name = ''.split('.')[-1] ctx = module.app.test_request_context() ctx.push() spec = APISpec(title=service_name, version='1.0.0', plugins=(FlaskRestyPlugin(), ), **options) schemas = get_subclasses(module.schemas, Schema) for schema in schemas: spec.definition(prettify_schema_name(schema), schema=schema) for view in get_subclasses(module.views, ApiView): try: spec.add_path(view=view, tag=True) except KeyError: pass # means that the view is not registered. move along return json.dumps(spec.to_dict(), indent=2)
def build_openapi_spec(): """Create OpenAPI definition.""" spec = APISpec( title="reana-job-controller", version=__version__, info=dict(description="REANA Job Controller API"), plugins=[ "apispec.ext.flask", "apispec.ext.marshmallow", ], ) # Add marshmallow models to specification spec.definition("Job", schema=Job) spec.definition("JobRequest", schema=JobRequest) # Collect OpenAPI docstrings from Flask endpoints for key in current_app.view_functions: if key != "static" and key != "get_openapi_spec": spec.add_path(view=current_app.view_functions[key]) return spec.to_dict()
def test_plugins_order(self): """Test plugins execution order in APISpec.add_path - All path helpers are called, then all operation helpers, then all response helpers. - At each step, helpers are executed in the order the plugins are passed to APISpec. """ output = [] spec = APISpec( title='Swagger Petstore', version='1.0.0', openapi_version='3.0.0', plugins=(self.OrderedPlugin(1, output), self.OrderedPlugin(2, output)), ) spec.add_path('/path', operations={'get': {'responses': {200: {}}}}) assert output == [ 'plugin_1_path', 'plugin_2_path', 'plugin_1_operations', 'plugin_2_operations', ]
def spec(schemas, views): spec = APISpec( title='test api', version='0.1.0', plugins=(FlaskRestyPlugin(), ), ) spec.definition('Foo', schema=schemas['foo']) spec.add_path(view=views['foo_list']) spec.add_path(view=views['foo']) spec.add_path(view=views['foo_baz']) spec.add_path(view=views['bar']) return spec.to_dict()
def test_resolve_schema_dict_auto_reference_return_none(self, schema): # this resolver return None def resolver(schema): return None spec = APISpec( title='Test auto-reference', version='0.1', openapi_version='2.0', plugins=(MarshmallowPlugin(schema_name_resolver=resolver, ), ), ) assert {} == get_definitions(spec) spec.definition('analysis', schema=schema) spec.add_path( '/test', operations={ 'get': { 'responses': { '200': { 'schema': { '$ref': '#/definitions/analysis', }, }, }, }, }, ) # Other shemas not yet referenced definitions = get_definitions(spec) assert 1 == len(definitions) assert 'analysis' in definitions # Inspect/Read objects will not auto reference because resolver func # return None json.dumps(spec.to_dict()) # Other shema still not referenced definitions = get_definitions(spec) assert 1 == len(definitions)
spec = APISpec( title='mypackage', version='0.0.1', info=dict( description='${description}' ), plugins=['apispec.ext.marshmallow'] ) class PersonSchema(Schema): age = fields.Int() name = fields.String() spec.definition('Person', schema=PersonSchema) spec.add_path( path='/randomPerson', operations=dict( get=dict( responses={ '${op.responses().success().code()}': { 'schema': {'$ref': '#/definitions/Person'} } } ) ) )