def __init__(self, prefix=None, default_authenticator=None, default_headers_schema=None, swagger_generator=None, swagger_path='/swagger', swagger_ui_path='/swagger/ui'): self.prefix = normalize_prefix(prefix) self._paths = defaultdict(dict) self.default_authenticator = default_authenticator self.default_headers_schema = default_headers_schema self.swagger_generator = swagger_generator or SwaggerV2Generator() self.swagger_path = swagger_path self.swagger_ui_path = swagger_ui_path
def test_path_parameter_types_must_be_the_same_for_same_path(self): rebar = Rebar() registry = rebar.create_handler_registry() @registry.handles(rule='/foos/<string:foo_uid>', method='GET') def get_foo(foo_uid): pass @registry.handles(rule='/foos/<int:foo_uid>', method='PATCH') def update_foo(foo_uid): pass generator = SwaggerV2Generator() with self.assertRaises(ValueError): generator.generate(registry)
def test_swagger_generator_v2(registry, swagger_version, expected_swagger): if swagger_version == 2: swagger_jsonschema = SWAGGER_V2_JSONSCHEMA generator = SwaggerV2Generator() elif swagger_version == 3: swagger_jsonschema = SWAGGER_V3_JSONSCHEMA generator = SwaggerV3Generator() else: raise ValueError("Unknown swagger_version: {}".format(swagger_version)) validate_swagger(expected_swagger, schema=swagger_jsonschema) swagger = generator.generate(registry) result = json.dumps(swagger, indent=2, sort_keys=True) expected = json.dumps(expected_swagger, indent=2, sort_keys=True) assert result == expected
def __init__( self, prefix=None, default_authenticators=None, default_headers_schema=None, default_mimetype=None, swagger_generator=None, spec_path="/swagger", spec_ui_path="/swagger/ui", ): # default_authenticators can be a single Authenticator, a list of Authenticators, or None. if isinstance(default_authenticators, Authenticator): default_authenticators = [default_authenticators] elif default_authenticators is None: default_authenticators = [] self.prefix = normalize_prefix(prefix) self._paths = defaultdict(dict) self.default_authenticators = default_authenticators self.default_headers_schema = default_headers_schema self.default_mimetype = default_mimetype self.swagger_generator = swagger_generator or SwaggerV2Generator() self.spec_path = spec_path self.spec_ui_path = spec_ui_path
import marshmallow as m from flask_rebar import Rebar from flask_rebar import HeaderApiKeyAuthenticator from flask_rebar import compat from flask_rebar.swagger_generation import SwaggerV2Generator, SwaggerV3Generator rebar = Rebar() registry = rebar.create_handler_registry() swagger_v2_generator = SwaggerV2Generator() swagger_v3_generator_with_hidden = SwaggerV3Generator(include_hidden=True) normal_swagger_v3_generator = SwaggerV3Generator() authenticator = HeaderApiKeyAuthenticator(header="x-auth") default_authenticator = HeaderApiKeyAuthenticator(header="x-another", name="default") class HeaderSchema(m.Schema): user_id = compat.set_data_key(field=m.fields.String(required=True), key="X-UserId") class FooSchema(m.Schema): __swagger_title__ = "Foo" uid = m.fields.String() name = m.fields.String() class NestedFoosSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True)
def test_swagger_v2_generator_non_registry_parameters(): host = "swag.com" schemes = ["http"] consumes = ["application/json"] produces = ["application/json"] title = "Test API" version = "2.1.0" description = "Foo Bar Baz" class Error(m.Schema): message = m.fields.String() details = m.fields.Dict() generator = SwaggerV2Generator( host=host, schemes=schemes, consumes=consumes, produces=produces, title=title, version=version, description=description, default_response_schema=Error(), tags=[ Tag( name="bar", description="baz", external_docs=ExternalDocumentation(url="http://bardocs.com", description="qux"), ) ], ) rebar = Rebar() registry = rebar.create_handler_registry() swagger = generator.generate(registry) expected_swagger = { "swagger": "2.0", "host": host, "info": { "title": title, "version": version, "description": description }, "schemes": schemes, "consumes": consumes, "produces": produces, "securityDefinitions": {}, "tags": [{ "name": "bar", "description": "baz", "externalDocs": { "url": "http://bardocs.com", "description": "qux" }, }], "paths": {}, "definitions": { "Error": { "type": "object", "title": "Error", "properties": { "message": { "type": "string" }, "details": { "type": "object" }, }, } }, } validate_swagger(expected_swagger) _assert_dicts_equal(swagger, expected_swagger)
"details": { "type": "object" }, }, } } }, } validate_swagger(expected_swagger, SWAGGER_V3_JSONSCHEMA) _assert_dicts_equal(swagger, expected_swagger) @pytest.mark.parametrize( "generator", [SwaggerV2Generator(), SwaggerV3Generator()]) def test_path_parameter_types_must_be_the_same_for_same_path(generator): rebar = Rebar() registry = rebar.create_handler_registry() @registry.handles(rule="/foos/<string:foo_uid>", method="GET") def get_foo(foo_uid): pass @registry.handles(rule="/foos/<int:foo_uid>", method="PATCH") def update_foo(foo_uid): pass with pytest.raises(ValueError): generator.generate(registry)
from flask_rebar import Rebar, HeaderApiKeyAuthenticator, compat from flask_rebar.authenticators import Authenticator, USE_DEFAULT from flask_rebar.swagger_generation import SwaggerV2Generator, SwaggerV3Generator from flask_rebar.swagger_generation.authenticator_to_swagger import ( AuthenticatorConverterRegistry, AuthenticatorConverter, HeaderApiKeyConverter, ) rebar = Rebar() registry = rebar.create_handler_registry() authenticator_converter_registry = AuthenticatorConverterRegistry() swagger_v2_generator = SwaggerV2Generator( authenticator_converter_registry=authenticator_converter_registry) swagger_v3_generator = SwaggerV3Generator( authenticator_converter_registry=authenticator_converter_registry) # If we ever add a HTTP 'Authorization' authenticator then use that. class FakeHTTPAuthorizationAuthenticator(Authenticator): name = "basicAuth" schema = "basic" def authenticate(self): return class HTTPAuthorizationAuthenticatorConverter(AuthenticatorConverter):
def test_generate_swagger(self): rebar = Rebar() registry = rebar.create_handler_registry() authenticator = HeaderApiKeyAuthenticator(header='x-auth') default_authenticator = HeaderApiKeyAuthenticator(header='x-another', name='default') class HeaderSchema(m.Schema): user_id = m.fields.String(load_from='x-userid', required=True) class FooSchema(m.Schema): __swagger_title__ = 'Foo' uid = m.fields.String() name = m.fields.String() class ListOfFooSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True) class FooUpdateSchema(m.Schema): __swagger_title = 'FooUpdate' name = m.fields.String() class FooListSchema(m.Schema): name = m.fields.String() @registry.handles(rule='/foos/<uuid_string:foo_uid>', method='GET', marshal_schema={200: FooSchema()}, headers_schema=HeaderSchema()) def get_foo(foo_uid): """helpful description""" pass @registry.handles(rule='/foos/<foo_uid>', method='PATCH', marshal_schema={200: FooSchema()}, request_body_schema=FooUpdateSchema(), authenticator=authenticator) def update_foo(foo_uid): pass @registry.handles( rule='/foos', method='GET', marshal_schema={200: ListOfFooSchema()}, query_string_schema=FooListSchema(), authenticator=None # Override the default! ) def list_foos(): pass registry.set_default_authenticator(default_authenticator) host = 'swag.com' schemes = ['http'] consumes = ['application/json'] produces = ['application/vnd.plangrid+json'] title = 'Test API' version = '2.1.0' class Error(m.Schema): message = m.fields.String() details = m.fields.Dict() generator = SwaggerV2Generator(host=host, schemes=schemes, consumes=consumes, produces=produces, title=title, version=version, default_response_schema=Error()) swagger = generator.generate(registry) expected_swagger = { 'swagger': '2.0', 'host': host, 'info': { 'title': title, 'version': version, 'description': '', }, 'schemes': schemes, 'consumes': consumes, 'produces': produces, 'security': [{ 'default': [] }], 'securityDefinitions': { 'sharedSecret': { 'type': 'apiKey', 'in': 'header', 'name': 'x-auth' }, 'default': { 'type': 'apiKey', 'in': 'header', 'name': 'x-another' } }, 'paths': { '/foos/{foo_uid}': { 'parameters': [{ 'name': 'foo_uid', 'in': 'path', 'required': True, 'type': 'string' }], 'get': { 'operationId': 'get_foo', 'description': 'helpful description', 'responses': { '200': { 'description': 'Foo', 'schema': { '$ref': '#/definitions/Foo' } }, 'default': { 'description': 'Error', 'schema': { '$ref': '#/definitions/Error' } } }, 'parameters': [{ 'name': 'x-userid', 'in': 'header', 'required': True, 'type': 'string' }] }, 'patch': { 'operationId': 'update_foo', 'responses': { '200': { 'description': 'Foo', 'schema': { '$ref': '#/definitions/Foo' } }, 'default': { 'description': 'Error', 'schema': { '$ref': '#/definitions/Error' } } }, 'parameters': [{ 'name': 'FooUpdateSchema', 'in': 'body', 'required': True, 'schema': { '$ref': '#/definitions/FooUpdateSchema' } }], 'security': [{ 'sharedSecret': [] }] } }, '/foos': { 'get': { 'operationId': 'list_foos', 'responses': { '200': { 'description': 'ListOfFooSchema', 'schema': { '$ref': '#/definitions/ListOfFooSchema' } }, 'default': { 'description': 'Error', 'schema': { '$ref': '#/definitions/Error' } } }, 'parameters': [{ 'name': 'name', 'in': 'query', 'required': False, 'type': 'string' }], 'security': [] } } }, 'definitions': { 'Foo': { 'type': 'object', 'title': 'Foo', 'properties': { 'uid': { 'type': 'string' }, 'name': { 'type': 'string' } } }, 'FooUpdateSchema': { 'type': 'object', 'title': 'FooUpdateSchema', 'properties': { 'name': { 'type': 'string' } } }, 'ListOfFooSchema': { 'type': 'object', 'title': 'ListOfFooSchema', 'properties': { 'data': { 'type': 'array', 'items': { '$ref': '#/definitions/Foo' } } } }, 'Error': { 'type': 'object', 'title': 'Error', 'properties': { 'message': { 'type': 'string' }, 'details': { 'type': 'object' } } } } } # Uncomment these lines to just dump the result to the terminal: # import json # print(json.dumps(swagger, indent=2)) # self.assertTrue(False) # This will raise an error if validation fails validate_swagger(expected_swagger) self.assertEqual(swagger, expected_swagger)
def test_generate_swagger(self): rebar = Rebar() registry = rebar.create_handler_registry() authenticator = HeaderApiKeyAuthenticator(header="x-auth") default_authenticator = HeaderApiKeyAuthenticator( header="x-another", name="default" ) class HeaderSchema(m.Schema): user_id = compat.set_data_key( field=m.fields.String(required=True), key="X-UserId" ) class FooSchema(m.Schema): __swagger_title__ = "Foo" uid = m.fields.String() name = m.fields.String() class NestedFoosSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True) class FooUpdateSchema(m.Schema): __swagger_title = "FooUpdate" name = m.fields.String() class NameAndOtherSchema(m.Schema): name = m.fields.String() other = m.fields.String() @registry.handles( rule="/foos/<uuid_string:foo_uid>", method="GET", marshal_schema={200: FooSchema()}, headers_schema=HeaderSchema(), ) def get_foo(foo_uid): """helpful description""" pass @registry.handles( rule="/foos/<foo_uid>", method="PATCH", marshal_schema={200: FooSchema()}, request_body_schema=FooUpdateSchema(), authenticator=authenticator, ) def update_foo(foo_uid): pass # Test using Schema(many=True) without using a nested Field. # https://github.com/plangrid/flask-rebar/issues/41 @registry.handles( rule="/foo_list", method="GET", marshal_schema={200: FooSchema(many=True)}, authenticator=None, # Override the default! ) def list_foos(): pass @registry.handles( rule="/foos", method="GET", marshal_schema={200: NestedFoosSchema()}, query_string_schema=NameAndOtherSchema(), authenticator=None, # Override the default! ) def nested_foos(): pass @registry.handles(rule="/tagged_foos", tags=["bar", "baz"]) def tagged_foos(): pass registry.set_default_authenticator(default_authenticator) host = "swag.com" schemes = ["http"] consumes = ["application/json"] produces = ["application/json"] title = "Test API" version = "2.1.0" class Error(m.Schema): message = m.fields.String() details = m.fields.Dict() generator = SwaggerV2Generator( host=host, schemes=schemes, consumes=consumes, produces=produces, title=title, version=version, default_response_schema=Error(), tags=[ Tag( name="bar", description="baz", external_docs=ExternalDocumentation( url="http://bardocs.com", description="qux" ), ) ], ) swagger = generator.generate(registry) expected_swagger = { "swagger": "2.0", "host": host, "info": {"title": title, "version": version, "description": ""}, "schemes": schemes, "consumes": consumes, "produces": produces, "security": [{"default": []}], "securityDefinitions": { "sharedSecret": {"type": "apiKey", "in": "header", "name": "x-auth"}, "default": {"type": "apiKey", "in": "header", "name": "x-another"}, }, "tags": [ { "name": "bar", "description": "baz", "externalDocs": {"url": "http://bardocs.com", "description": "qux"}, } ], "paths": { "/foos/{foo_uid}": { "parameters": [ { "name": "foo_uid", "in": "path", "required": True, "type": "string", } ], "get": { "operationId": "get_foo", "description": "helpful description", "responses": { "200": { "description": "Foo", "schema": {"$ref": "#/definitions/Foo"}, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "parameters": [ { "name": "X-UserId", "in": "header", "required": True, "type": "string", } ], }, "patch": { "operationId": "update_foo", "responses": { "200": { "description": "Foo", "schema": {"$ref": "#/definitions/Foo"}, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "parameters": [ { "name": "FooUpdateSchema", "in": "body", "required": True, "schema": {"$ref": "#/definitions/FooUpdateSchema"}, } ], "security": [{"sharedSecret": []}], }, }, "/foo_list": { "get": { "operationId": "list_foos", "responses": { "200": { "description": "Foo", "schema": { "type": "array", "items": {"$ref": "#/definitions/Foo"}, }, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "security": [], } }, "/foos": { "get": { "operationId": "nested_foos", "responses": { "200": { "description": "NestedFoosSchema", "schema": {"$ref": "#/definitions/NestedFoosSchema"}, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "parameters": [ { "name": "name", "in": "query", "required": False, "type": "string", }, { "name": "other", "in": "query", "required": False, "type": "string", }, ], "security": [], } }, "/tagged_foos": { "get": { "tags": ["bar", "baz"], "operationId": "tagged_foos", "responses": { "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, } }, } }, }, "definitions": { "Foo": { "type": "object", "title": "Foo", "properties": { "uid": {"type": "string"}, "name": {"type": "string"}, }, }, "FooUpdateSchema": { "type": "object", "title": "FooUpdateSchema", "properties": {"name": {"type": "string"}}, }, "NestedFoosSchema": { "type": "object", "title": "NestedFoosSchema", "properties": { "data": { "type": "array", "items": {"$ref": "#/definitions/Foo"}, } }, }, "Error": { "type": "object", "title": "Error", "properties": { "message": {"type": "string"}, "details": {"type": "object"}, }, }, }, } # Uncomment these lines to just dump the result to the terminal: # import json # print(json.dumps(swagger, indent=2)) # print(json.dumps(expected_swagger, indent=2)) # self.assertTrue(False) # This will raise an error if validation fails validate_swagger(expected_swagger) self.assertEqual(swagger, expected_swagger)