Пример #1
0
    def test_schema_name_resolver_returns_none_v3(self, pet_schema):
        def resolver(schema):
            return None

        spec = APISpec(
            title="Test resolver returns None",
            version="0.1",
            openapi_version="3.0.0",
            plugins=(MarshmallowPlugin(schema_name_resolver=resolver),),
        )
        spec.path(
            path="/pet",
            operations={
                "get": {
                    "responses": {
                        200: {"content": {"application/json": {"schema": pet_schema}}}
                    }
                }
            },
        )
        get = get_paths(spec)["/pet"]["get"]
        assert (
            "properties"
            in get["responses"]["200"]["content"]["application/json"]["schema"]
        )
Пример #2
0
    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.components.schema('analysis', schema=schema)
        spec.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
Пример #3
0
def create_app(config_filename=None):
    if config_filename is None:
        conf = default_config.copy()
    else:
        conf = read_conf(config_filename)
    app = falcon.API()
    rethink_factory = RethinkDBFactory(**conf["rethinkdb"])

    user_resource = Users(rethink_factory)
    card_resource = Cards(rethink_factory)

    app.add_route("/users", user_resource)
    app.add_route("/cards", card_resource)

    # Create an APISpec
    spec = APISpec(
        title='Swagger Prelaunch Spec',
        version='1.0.0',
        openapi_version='2.0',
        plugins=[
            FalconPlugin(app),
            MarshmallowPlugin(),
        ],
    )

    # Register entities and paths
    spec.components.schema('User', schema=User.schema())
    spec.components.schema('Card', schema=Card.schema())

    spec.path(resource=user_resource)
    spec.path(resource=card_resource)

    return app, spec
Пример #4
0
def generate_api_docs(filename, api_version, openapi_version):
    """
        Generates swagger (openapi) yaml from routes' docstrings (using apispec library).
    """
    from apispec import APISpec
    from apispec_webframeworks.flask import FlaskPlugin

    apidoc = APISpec(
        title="Grafolean API",
        version=api_version,
        openapi_version=openapi_version,
        plugins=[FlaskPlugin()],
        info={
            "description":
                "> IMPORTANT: API is under development and is **not final yet** - breaking changes might occur.\n\n" \
                "Grafolean is designed API-first. In other words, every functionality of the system is accessible through the API " \
                "described below. This allows integration with external systems so that (given the permissions) they too can " \
                "enter values, automatically modify entities, set up dashboards... Everything that can be done through frontend " \
                "can also be achieved through API.\n\n" \
                "This documentation is also available as Swagger/OpenAPI definition: [OAS2](./swagger2.yml) / [OAS3](./swagger3.yml)."
        }
    )

    for apidoc_schemas_func in [users_apidoc_schemas, accounts_apidoc_schemas, admin_apidoc_schemas]:
        for schema_name, schema in apidoc_schemas_func():
            apidoc.components.schema(schema_name, schema)

    with app.test_request_context():
        for rule in app.url_map.iter_rules():
            view = app.view_functions.get(rule.endpoint)
            apidoc.path(view=view)

    with open(filename, 'w') as openapi_yaml_file:
        openapi_yaml_file.write(apidoc.to_yaml())
Пример #5
0
    def test_resolve_schema_dict_auto_reference(self, schema):
        def resolver(schema):
            return schema.__name__

        spec = APISpec(
            title="Test auto-reference",
            version="0.1",
            openapi_version="2.0",
            plugins=(SerpycoPlugin(
                schema_name_resolver=schema_name_resolver), ),
        )
        assert {} == get_definitions(spec)

        spec.components.schema("analysis", schema=schema)
        spec.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_exclude_sample" in definitions
Пример #6
0
    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),),
        )
        with pytest.raises(KeyError):
            get_schemas(spec)

        spec.components.schema("analysis", schema=schema)
        spec.path(
            "/test",
            operations={
                "get": {
                    "responses": {
                        "200": {"schema": build_ref(spec, "schema", "analysis")}
                    }
                }
            },
        )
        definitions = get_schemas(spec)
        assert 3 == len(definitions)

        assert "analysis" in definitions
        assert "SampleSchema" in definitions
        assert "RunSchema" in definitions
def generate_swagger_file(handlers, file_location):
    """Automatically generates Swagger spec file based on RequestHandler
    docstrings and saves it to the specified file_location.
    """

    # Starting to generate Swagger spec file. All the relevant
    # information can be found from here https://apispec.readthedocs.io/
    spec = APISpec(
        title="Car Brand API",
        version="1.0.0",
        openapi_version="3.0.2",
        info=dict(description="Documentation for the Car Brand API"),
        plugins=[TornadoPlugin(), MarshmallowPlugin()],
        servers=[
            {
                "url": "http://localhost:8888/",
                "description": "Local environment",
            },
        ],
    )
    # Looping through all the handlers and trying to register them.
    # Handlers without docstring will raise errors. That's why we
    # are catching them silently.
    for handler in handlers:
        try:
            spec.path(urlspec=handler)
        except APISpecError:
            pass

    # Write the Swagger file into specified location.
    with open(file_location, "w", encoding="utf-8") as file:
        json.dump(spec.to_dict(), file, ensure_ascii=False, indent=4)
Пример #8
0
    def test_schema_uses_ref_if_available_name_resolver_returns_none_v3(self):
        def resolver(schema):
            return None

        spec = APISpec(
            title="Test auto-reference",
            version="0.1",
            openapi_version="3.0.0",
            plugins=(MarshmallowPlugin(schema_name_resolver=resolver),),
        )
        spec.components.schema("Pet", schema=PetSchema)
        spec.path(
            path="/pet",
            operations={
                "get": {
                    "responses": {
                        200: {"content": {"application/json": {"schema": PetSchema}}}
                    }
                }
            },
        )
        get = get_paths(spec)["/pet"]["get"]
        assert get["responses"]["200"]["content"]["application/json"][
            "schema"
        ] == build_ref(spec, "schema", "Pet")
def get_json(app: Chalice,
             route_functions: dict,
             route_prefix: str,
             version="1.0.0"):
    spec = APISpec(
        title=app.app_name,
        version=version,
        openapi_version="3.0.2",
        plugins=[generate_plugin(app)(),
                 MarshmallowPlugin()],
        servers=[{
            "url": f"/{route_prefix}",
            "description": f"Host on /"
        }],
    )

    fn_list = {[fn_name.view_name for fn_name in r.values()][0]
               for path, r in app.routes.items()}
    for fn_name in [
            fn_name for fn_name in fn_list if fn_name in route_functions
    ]:
        try:
            spec.path(view=route_functions[fn_name])
        except (TypeError, KeyError, ValueError) as e:
            logging.warning(f"Error parsing docstring: {e}")
    return json.dumps(spec.to_dict())
Пример #10
0
    def _apispec(self):

        info = {}
        if self.description is not None:
            info["description"] = self.description
        if self.terms_of_service is not None:
            info["termsOfService"] = self.terms_of_service
        if self.contact is not None:
            info["contact"] = self.contact
        if self.license is not None:
            info["license"] = self.license

        spec = APISpec(
            title=self.title,
            version=self.version,
            openapi_version=self.openapi_version,
            plugins=[MarshmallowPlugin()],
            info=info,
        )

        for route in self.routes:
            if self.routes[route].description:
                operations = yaml_utils.load_operations_from_docstring(
                    self.routes[route].description)
                spec.path(path=route, operations=operations)

        for name, schema in self.schemas.items():
            spec.components.schema(name, schema=schema)

        return spec
Пример #11
0
def document_endpoint_oauth2_authentication(
        spec: APISpec,
        *,
        endpoint: str,
        method: str,
        required_scopes: List[str],
        unauthorized_status_code: int = 401,
        forbidden_status_code: int = 403):
    spec.path(
        endpoint,
        operations={
            method.lower(): {
                "responses": {
                    str(unauthorized_status_code): {
                        "description":
                        "No permission -- see authorization schemes",
                        "schema": {
                            "type": "string"
                        },
                    },
                    str(forbidden_status_code): {
                        "description":
                        "Request forbidden -- authorization will not help",
                        "schema": {
                            "type": "string"
                        },
                    },
                },
                "security": [{
                    "oauth2": required_scopes
                }],
            }
        },
    )
Пример #12
0
def get_spec():
    """
    Produce the OpenAPIv3 spec document.

    :rtype: dict
    """
    spec = APISpec(
        title="rest-demo-api",
        version=__version__,
        openapi_version="3.0.2",
        plugins=[FlaskPlugin(), MarshmallowPlugin()],
    )

    app = get_app()
    # Useful for debugging
    # print(app.view_functions)
    spec.path("/authors", view=app.view_functions["authors"], app=app)
    spec.path("/authors/{author_id}",
              view=app.view_functions["author"],
              app=app)
    spec.path("/authors/{author_id}/quotes",
              view=app.view_functions["authorquotes"],
              app=app)
    spec.path("/quotes", view=app.view_functions["quotes"], app=app)
    spec.path("/quotes/{quote_id}", view=app.view_functions["quote"], app=app)
    return spec.to_dict()
Пример #13
0
 def test_schema_uses_ref_if_available_name_resolver_returns_none_v3(self):
     def resolver(schema):
         return None
     spec = APISpec(
         title='Test auto-reference',
         version='0.1',
         openapi_version='3.0.0',
         plugins=(
             MarshmallowPlugin(schema_name_resolver=resolver,),
         ),
     )
     spec.components.schema('Pet', schema=PetSchema)
     spec.path(
         path='/pet',
         operations={
             'get': {
                 'responses': {
                     200: {
                         'content': {
                             'application/json': {
                                 'schema': PetSchema,
                             },
                         },
                     },
                 },
             },
         },
     )
     get = get_paths(spec)['/pet']['get']
     assert get['responses'][200]['content']['application/json']['schema']['$ref'] == ref_path(
         spec,
     ) + 'Pet'
def add_paths(spec: APISpec):
    spec.path(
        path='/category/{id}',
        parameters=[param('id', 'ID of a Category')],
        operations=dict(get=method(responses=[
            response(OK, 'Information about a category', CategorySchema),
        ])),
    )
Пример #15
0
def run_app(
    app: Flask,
    name: str,
    version: str,
    api_version: str,
    port: int,
    dataclasses: Optional[List[Type[JsonSchemaMixin]]] = None,
    print_spec: bool = False,
) -> None:

    spec = APISpec(
        title=f"{name} ({version})",
        version=api_version,
        openapi_version="3.0.2",
        plugins=[FlaskPlugin(), DataclassesPlugin()],
    )

    if dataclasses is not None:
        for dc in dataclasses:
            spec.components.schema(dc.__name__, schema=dc)

    with app.test_request_context():
        for rule in app.url_map.iter_rules():
            if rule.endpoint != "static":
                spec.path(view=app.view_functions[rule.endpoint])

    if print_spec:
        print(spec.to_yaml())
        return

    @app.route("/swagger/api/swagger.json", methods=["GET"])
    def get_swagger() -> str:
        return jsonify(spec.to_dict())

    @app.errorhandler(Arcor2Exception)
    def handle_bad_request_general(e: Arcor2Exception) -> Tuple[str, int]:
        return json.dumps(str(e)), 400

    @app.errorhandler(FlaskException)
    def handle_bad_request_intentional(e: FlaskException) -> Tuple[str, int]:
        return json.dumps(str(e)), e.error_code

    SWAGGER_URL = "/swagger"

    swaggerui_blueprint = get_swaggerui_blueprint(
        SWAGGER_URL,
        "./api/swagger.json"  # Swagger UI static files will be mapped to '{SWAGGER_URL}/dist/'
    )

    # Register blueprint at URL
    app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)

    if not env.get_bool("ARCOR2_REST_API_DEBUG", False):
        # turn off logging each endpoint call by default
        log = logging.getLogger("werkzeug")
        log.setLevel(logging.ERROR)

    app.run(host="0.0.0.0", port=port)
Пример #16
0
    def oas_schema(self, pkg):
        spec = APISpec(
            title=pkg.meta["name"].capitalize(),
            version=pkg.meta["version"],
            openapi_version=self.config["oas_version"],
            plugins=[MarshmallowPlugin()],
        )

        for ctrl in pkg.controllers:
            if not isinstance(ctrl, BaseHttpController):
                continue

            routes = {}

            for func, handler in ctrl.handlers:
                if not handler.status:
                    warnings.warn(f"No @returns for {func}, cannot generate OAS3 schema for this handler")
                    break

                abspath = handler.path_full
                method = handler.method.lower()

                if abspath not in routes:
                    routes[abspath] = {}

                if method not in routes[abspath]:
                    routes[abspath][method] = dict(
                        responses={},
                        parameters=[]
                    )

                route = routes[abspath][method]
                responses = route["responses"]
                parameters = route["parameters"]

                for location, schema_cls in handler.schemas:
                    if location == "response":
                        if not schema_cls:
                            content = {}
                        else:
                            content = {"application/json": {"schema": schema_cls}}

                        responses[handler.status] = dict(
                            description=None,
                            content=content
                        )
                    elif location in ["path", "query", "header"]:
                        if not schema_cls:
                            continue

                        parameters.append({
                            "in": location,
                            "schema": schema_cls
                        })

                spec.path(handler.path_full, operations=routes[abspath])

        return spec.to_dict()
Пример #17
0
def test_openapi_tools_validate_v2():
    ma_plugin = MarshmallowPlugin()
    spec = APISpec(
        title="Pets", version="0.1", plugins=(ma_plugin,), openapi_version="2.0"
    )
    openapi = ma_plugin.converter

    spec.components.schema("Category", schema=CategorySchema)
    spec.components.schema("Pet", {"discriminator": "name"}, schema=PetSchema)

    spec.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",
                    },
                    openapi.field2parameter(
                        field=fields.List(
                            fields.Str(),
                            validate=validate.OneOf(["freddie", "roger"]),
                            location="querystring",
                        ),
                        default_in=None,
                        name="body",
                    ),
                ]
                + openapi.schema2parameters(PageSchema, default_in="query"),
                "responses": {200: {"schema": PetSchema, "description": "A pet"}},
            },
            "post": {
                "parameters": (
                    [
                        {
                            "name": "category_id",
                            "in": "path",
                            "required": True,
                            "type": "string",
                        }
                    ]
                    + openapi.schema2parameters(CategorySchema, default_in="body")
                ),
                "responses": {201: {"schema": PetSchema, "description": "A pet"}},
            },
        },
    )
    try:
        utils.validate_spec(spec)
    except exceptions.OpenAPIError as error:
        pytest.fail(str(error))
Пример #18
0
def add_paths(spec: APISpec):
    spec.path(
        path='/category/{id}',
        parameters=[param('id', 'Identifier of a category')],
        operations=dict(
            get=method(tags=['categories'],
                       responses=[
                           response_json(OK, 'Information about a category',
                                         CategorySchema),
                       ])),
    )
Пример #19
0
 def test_plugin_operation_helper_is_used(self, openapi_version):
     spec = APISpec(
         title="Swagger Petstore",
         version="1.0.0",
         openapi_version=openapi_version,
         plugins=(self.test_plugin_factory(), ),
     )
     spec.path("/path_2", operations={"post": {"responses": {"200": {}}}})
     paths = get_paths(spec)
     assert len(paths) == 1
     assert paths["/path_2"] == {"post": {"responses": {"201": {}}}}
Пример #20
0
 def test_plugin_operation_helper_is_used(self, openapi_version):
     spec = APISpec(
         title='Swagger Petstore',
         version='1.0.0',
         openapi_version=openapi_version,
         plugins=(self.test_plugin_factory(), ),
     )
     spec.path('/path_2', operations={'post': {'responses': {'200': {}}}})
     paths = get_paths(spec)
     assert len(paths) == 1
     assert paths['/path_2'] == {'post': {'responses': {'201': {}}}}
Пример #21
0
    def convert(self, yaml=False, references=True, ignorespec=None, **options):
        spec = APISpec(title=self.info.get('title'),
                       version=self.info.get('version'),
                       openapi_version=self.openapi,
                       plugins=[MultiOperationBuilderPlugin(references)],
                       **options)

        for requestitem in self.postman_collection.get_requestitems():
            spec.path(path=requestitem.get_request().path,
                      operations=Operation(requestitem,
                                           ignorespec=ignorespec).get())
        return spec.to_yaml() if yaml else spec.to_dict()
Пример #22
0
def document_response(spec: APISpec, *, endpoint: str, method: str,
                      status_code: int, response: dict):
    spec.path(
        endpoint,
        operations={
            method.lower(): {
                "responses": {
                    str(status_code): response
                }
            }
        },
    )
Пример #23
0
def test_path_summary():
    app = Starlette()
    plugin = StarlettePlugin(app)
    spec = APISpec(title="Test API",
                   version="0.0.1",
                   openapi_version="2.0",
                   plugins=[plugin])

    @app.route("/test")
    def test_endpoint(request):
        """This is the expected summary"""
        pass  # pragma: no cover

    @app.route("/test_with_doc")
    def test_endpoint_with_doc(request):
        """
        This is the expected summary 2
        ---
        responses:
            200:
                description: "ok"
        """
        pass  # pragma: no cover

    for endpoint in plugin.endpoints():
        spec.path(endpoint.path, endpoint=endpoint)

    assert spec.to_dict() == {
        "info": {
            "title": "Test API",
            "version": "0.0.1"
        },
        "paths": {
            "/test": {
                "get": {
                    "operationId": "get_test_endpoint",
                    "summary": "This is the expected summary",
                }
            },
            "/test_with_doc": {
                "get": {
                    "summary": "This is the expected summary 2",
                    "operationId": "get_test_endpoint_with_doc",
                    "responses": {
                        "200": {
                            "description": "ok"
                        }
                    },
                }
            },
        },
        "swagger": "2.0",
    }
Пример #24
0
    def test_path_called_twice_with_same_operations_parameters(
            self, openapi_version):
        """Test calling path twice with same operations or parameters

        operations and parameters being mutated by clean_operations and plugin helpers
        should not make path fail on second call
        """
        class TestPlugin(BasePlugin):
            def path_helper(self, path, operations, parameters, **kwargs):
                """Mutate operations and parameters"""
                operations.update(
                    {"post": {
                        "responses": {
                            "201": "201ResponseRef"
                        }
                    }})
                parameters.append("ParamRef_3")
                return path

        spec = APISpec(
            title="Swagger Petstore",
            version="1.0.0",
            openapi_version=openapi_version,
            plugins=[TestPlugin()],
        )

        path = "/pet/{petId}"
        parameters = ["ParamRef_1"]
        operation = {
            "parameters": ["ParamRef_2"],
            "responses": {
                "200": "200ResponseRef"
            },
        }

        spec.path(path=path,
                  operations={"get": operation},
                  parameters=parameters)
        spec.path(path=path,
                  operations={"put": operation},
                  parameters=parameters)
        operations = (get_paths(spec))[path]
        assert (operations["get"] == operations["put"] == {
            "parameters": [build_ref(spec, "parameter", "ParamRef_2")],
            "responses": {
                "200": build_ref(spec, "response", "200ResponseRef")
            },
        })
        assert operations["parameters"] == [
            build_ref(spec, "parameter", "ParamRef_1"),
            build_ref(spec, "parameter", "ParamRef_3"),
        ]
Пример #25
0
def build_openapi_spec(handlers: List[Tuple[str, Callable]]) -> APISpec:
    spec = APISpec(
        title='VGS Satellite management API',
        version='1.0.0',
        openapi_version='3.0.2',
        info={'description': 'The management API for VGS Satellite app'},
        plugins=[TornadoPlugin(), MarshmallowPlugin()],
    )

    for urlspec in handlers:
        spec.path(urlspec=urlspec)

    return spec
Пример #26
0
    def get_spec(self, references=True, ignorespec=None, **options) -> APISpec:
        spec = APISpec(title=self.info.get("title"),
                       version=self.info.get("version"),
                       openapi_version=self.openapi,
                       plugins=[MultiOperationBuilderPlugin(references)],
                       **options)

        for requestitem in self.postman_collection.get_requestitems():
            spec.path(
                path=requestitem.get_request().path,
                operations=Operation(requestitem, ignorespec=ignorespec).get(),
            )
        return spec
Пример #27
0
def create_spec(registry, zone=None, merge=None):
    title = registry.settings.get("openapi.title", "Untitled")
    version = registry.settings.get("openapi.version", "0.0.0")
    name_resolver = DottedNameResolver()
    MarshmallowPlugin = name_resolver.maybe_resolve(
        registry.settings.get("openapi.plugin",
                              "apispec.ext.marshmallow.MarshmallowPlugin"))
    marshmallow_plugin = MarshmallowPlugin(
        schema_name_resolver=schema_name_resolver)
    spec = APISpec(
        title=title,
        version=version,
        openapi_version="3.0.2",
        plugins=[marshmallow_plugin],
    )
    for path, operations in list_paths(registry.introspector):
        final_ops = dict()
        for method, view in operations.items():
            if zone is not None and zone != view.get("api_zone"):
                continue
            summary, descr, user_op = split_docstring(view["callable"].__doc__)
            op = {
                "responses": dict(),
                "parameters": [],
            }
            if summary:
                op["summary"] = summary
            if descr:
                op["description"] = descr
            set_url_params(spec, op, view)
            if "validate" in view:
                if method == "get":
                    set_query_params(spec, op, view)
                else:
                    set_request_body(spec, op, view)
            if "marshal" in view:
                set_response_body(spec, op, view)
            set_tag(spec, op, view)
            final_op = utils.deepupdate(op, user_op)
            final_op = utils.deepupdate(final_op, view.get("api_spec", dict()))

            # We are required to have some response, so make one up.
            if not final_op["responses"]:
                final_op["responses"]["200"] = {
                    "description": "",
                }
            final_ops[method] = final_op
        spec.path(path, operations=final_ops)

    json = spec.to_dict()
    return _perform_merges(json, merge, registry.settings.get("openapi.merge"))
Пример #28
0
 def test_plugin_path_helper_is_used(self, openapi_version, return_none):
     spec = APISpec(
         title="Swagger Petstore",
         version="1.0.0",
         openapi_version=openapi_version,
         plugins=(self.test_plugin_factory(return_none),),
     )
     spec.path("/path_1")
     paths = get_paths(spec)
     assert len(paths) == 1
     if return_none:
         assert paths["/path_1"] == {}
     else:
         assert paths["/path_1_modified"] == {"get": {"responses": {"200": {}}}}
Пример #29
0
 def test_plugin_path_helper_is_used(self, openapi_version, return_none):
     spec = APISpec(
         title='Swagger Petstore',
         version='1.0.0',
         openapi_version=openapi_version,
         plugins=(self.test_plugin_factory(return_none), ),
     )
     spec.path('/path_1')
     paths = get_paths(spec)
     assert len(paths) == 1
     if return_none:
         assert paths['/path_1'] == {}
     else:
         assert paths['/path_1_modified'] == {'get': {'responses': {'200': {}}}}
Пример #30
0
    def test_schema_uses_ref_if_available_name_resolver_returns_none_v2(self):
        def resolver(schema):
            return None

        spec = APISpec(
            title="Test auto-reference",
            version="0.1",
            openapi_version="2.0",
            plugins=(MarshmallowPlugin(schema_name_resolver=resolver),),
        )
        spec.components.schema("Pet", schema=PetSchema)
        spec.path(
            path="/pet", operations={"get": {"responses": {200: {"schema": PetSchema}}}}
        )
        get = get_paths(spec)["/pet"]["get"]
        assert get["responses"][200]["schema"]["$ref"] == ref_path(spec) + "Pet"