Exemple #1
0
 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
Exemple #4
0
    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)
Exemple #10
0
    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)