Beispiel #1
0
    def test_rebar_can_be_url_prefixed(self):
        app = Flask(__name__)
        app.testing = True

        rebar = Rebar()
        registry_v1 = rebar.create_handler_registry(prefix="v1")
        registry_v2 = rebar.create_handler_registry(
            prefix="/v2/")  # Slashes shouldn't matter

        # We use the same endpoint to show that the swagger operationId gets set correctly
        # and the Flask endpoint gets prefixed
        register_endpoint(registry=registry_v1, endpoint="get_foo")
        register_endpoint(registry=registry_v2, endpoint="get_foo")

        rebar.init_app(app)

        for prefix in ("v1", "v2"):
            resp = app.test_client().get(
                prefix_url(prefix=prefix, url="/swagger/ui/"))
            self.assertEqual(resp.status_code, 200)

            swagger = get_swagger(test_client=app.test_client(), prefix=prefix)
            validate_swagger(swagger)

            self.assertEqual(
                swagger["paths"][prefix_url(
                    prefix=prefix,
                    url="/foos/{foo_uid}")]["get"]["operationId"],
                "get_foo",
            )
            resp = app.test_client().get(
                prefix_url(prefix=prefix, url="/foos/1"))
            self.assertEqual(resp.status_code, 200)
Beispiel #2
0
    def test_rebar_can_be_url_prefixed(self):
        app = Flask(__name__)
        app.testing = True

        rebar = Rebar()
        registry_v1 = rebar.create_handler_registry(prefix='v1')
        registry_v2 = rebar.create_handler_registry(
            prefix='/v2/')  # Slashes shouldn't matter

        # We use the same endpoint to show that the swagger operationId gets set correctly
        # and the Flask endpoint gets prefixed
        register_endpoint(registry=registry_v1, endpoint='get_foo')
        register_endpoint(registry=registry_v2, endpoint='get_foo')

        rebar.init_app(app)

        for prefix in ('v1', 'v2'):
            resp = app.test_client().get(
                prefix_url(prefix=prefix, url='/swagger/ui/'))
            self.assertEqual(resp.status_code, 200)

            swagger = get_swagger(test_client=app.test_client(), prefix=prefix)
            validate_swagger(swagger)

            self.assertEqual(
                swagger['paths'][prefix_url(
                    prefix=prefix,
                    url='/foos/{foo_uid}')]['get']['operationId'], 'get_foo')
            resp = app.test_client().get(
                prefix_url(prefix=prefix, url='/foos/1'))
            self.assertEqual(resp.status_code, 200)
Beispiel #3
0
    def test_swagger_endpoint_is_automatically_created(self):
        rebar = Rebar()
        rebar.create_handler_registry()
        app = create_rebar_app(rebar)

        resp = app.test_client().get('/swagger')

        self.assertEqual(resp.status_code, 200)

        validate_swagger(get_json_from_resp(resp))
Beispiel #4
0
    def test_swagger_can_be_set_to_v3(self):
        rebar = Rebar()
        rebar.create_handler_registry(swagger_generator=SwaggerV3Generator())
        app = create_rebar_app(rebar)

        resp = app.test_client().get("/swagger")
        self.assertEqual(resp.status_code, 200)
        validate_swagger(resp.json, SWAGGER_V3_JSONSCHEMA)

        resp = app.test_client().get("/swagger/ui/")
        self.assertEqual(resp.status_code, 200)
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 test_swagger_generators(registry, swagger_generator, expected_swagger):
    open_api_version = swagger_generator.get_open_api_version()
    if open_api_version == "2.0":
        swagger_jsonschema = SWAGGER_V2_JSONSCHEMA
    elif open_api_version == "3.0.2":
        swagger_jsonschema = SWAGGER_V3_JSONSCHEMA
    else:
        raise ValueError(
            "Unknown swagger_version: {}".format(open_api_version))

    validate_swagger(expected_swagger, schema=swagger_jsonschema)

    swagger = 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 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)
def test_swagger_v3_generator_non_registry_parameters():
    title = "Test API"
    version = "3.0.0"
    description = "testing testing 123"

    class Error(m.Schema):
        message = m.fields.String()
        details = m.fields.Dict()

    generator = SwaggerV3Generator(
        version=version,
        title=title,
        description=description,
        default_response_schema=Error(),
        tags=[
            Tag(
                name="bar",
                description="baz",
                external_docs=ExternalDocumentation(url="http://bardocs.com",
                                                    description="qux"),
            )
        ],
        servers=[
            Server(
                url="https://{username}.gigantic-server.com:{port}/{basePath}",
                description="The production API server",
                variables={
                    "username":
                    ServerVariable(
                        default="demo",
                        description=
                        "this value is assigned by the service provider, in this example `gigantic-server.com`",
                    ),
                    "port":
                    ServerVariable(default="8443", enum=["8443", "443"]),
                    "basePath":
                    ServerVariable(default="v2"),
                },
            )
        ],
    )

    rebar = Rebar()
    registry = rebar.create_handler_registry()

    swagger = generator.generate(registry)

    expected_swagger = {
        "openapi":
        "3.0.2",
        "info": {
            "title": title,
            "version": version,
            "description": description
        },
        "tags": [{
            "name": "bar",
            "description": "baz",
            "externalDocs": {
                "url": "http://bardocs.com",
                "description": "qux"
            },
        }],
        "servers": [{
            "url": "https://{username}.gigantic-server.com:{port}/{basePath}",
            "description": "The production API server",
            "variables": {
                "username": {
                    "default":
                    "demo",
                    "description":
                    "this value is assigned by the service provider, in this example `gigantic-server.com`",
                },
                "port": {
                    "enum": ["8443", "443"],
                    "default": "8443"
                },
                "basePath": {
                    "default": "v2"
                },
            },
        }],
        "paths": {},
        "components": {
            "schemas": {
                "Error": {
                    "type": "object",
                    "title": "Error",
                    "properties": {
                        "message": {
                            "type": "string"
                        },
                        "details": {
                            "type": "object"
                        },
                    },
                }
            }
        },
    }

    validate_swagger(expected_swagger, SWAGGER_V3_JSONSCHEMA)
    _assert_dicts_equal(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 = 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)
Beispiel #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)