From 224151c60cc65255ff57900f08a9ad56748ef249 Mon Sep 17 00:00:00 2001 From: Robbe Sneyders Date: Sat, 23 Nov 2024 23:08:41 +0100 Subject: [PATCH] Fix swagger UI for split specs --- connexion/middleware/swagger_ui.py | 2 +- connexion/spec.py | 2 +- examples/helloworld_async/hello.py | 10 ++-- examples/helloworld_async/spec/openapi.yaml | 57 +++++++++++++-------- examples/helloworld_async/spec/swagger.yaml | 41 +++++++++------ tests/test_mock.py | 21 ++++++++ 6 files changed, 90 insertions(+), 43 deletions(-) diff --git a/connexion/middleware/swagger_ui.py b/connexion/middleware/swagger_ui.py index 3f701bcb0..3a31be5c2 100644 --- a/connexion/middleware/swagger_ui.py +++ b/connexion/middleware/swagger_ui.py @@ -63,7 +63,7 @@ def _base_path_for_prefix(self, request: StarletteRequest) -> str: "route_root_path", request.scope.get("root_path", "") ).rstrip("/") - def _spec_for_prefix(self, request): + def _spec_for_prefix(self, request) -> dict: """ returns a spec with a modified basePath / servers block which corresponds to the incoming request path. diff --git a/connexion/spec.py b/connexion/spec.py index 40fe46d70..83322b1c4 100644 --- a/connexion/spec.py +++ b/connexion/spec.py @@ -204,7 +204,7 @@ def enforce_string_keys(obj): return OpenAPISpecification(spec, base_uri=base_uri) def clone(self): - return type(self)(copy.deepcopy(self._raw_spec)) + return type(self)(copy.deepcopy(self._spec)) @classmethod def load(cls, spec, *, arguments=None): diff --git a/examples/helloworld_async/hello.py b/examples/helloworld_async/hello.py index 2410eea3b..e35989d63 100755 --- a/examples/helloworld_async/hello.py +++ b/examples/helloworld_async/hello.py @@ -3,19 +3,17 @@ import connexion -async def test(): +def pet(id_): pass -async def post_greeting(name: str): - await test() - return f"Hello {name}", 201 +def pets(): + return 200 app = connexion.AsyncApp(__name__, specification_dir="spec") app.add_api("openapi.yaml", arguments={"title": "Hello World Example"}) -app.add_api("swagger.yaml", arguments={"title": "Hello World Example"}) - +# app.add_api("swagger.yaml", arguments={"title": "Hello World Example"}) if __name__ == "__main__": app.run(f"{Path(__file__).stem}:app", port=8080) diff --git a/examples/helloworld_async/spec/openapi.yaml b/examples/helloworld_async/spec/openapi.yaml index dc106ff1b..d6fbf94de 100644 --- a/examples/helloworld_async/spec/openapi.yaml +++ b/examples/helloworld_async/spec/openapi.yaml @@ -1,30 +1,47 @@ -openapi: "3.0.0" +openapi: 3.0.0 info: - title: Hello World - version: "1.0" + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT + servers: - url: /openapi paths: - /greeting/{name}: - post: - summary: Generate greeting - description: Generates a greeting message. - operationId: hello.post_greeting + /pets: + get: + operationId: hello.pets + summary: List all pets + responses: + '200': + description: A paged array of pets + content: + application/json: + schema: + $ref: "components.yaml#/components/schemas/Pets" + default: + description: Unexpected error + content: + application/json: + schema: + $ref: "components.yaml#/components/schemas/Error" + + '/pets/{petId}': + get: + operationId: hello.pet + summary: Info for a specific pet responses: '200': - description: greeting response + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "components.yaml#/components/schemas/Pet" + default: + description: Unexpected error content: - text/plain: + application/json: schema: - type: string - example: "hello dave!" - parameters: - - name: name - in: path - description: Name of the person to greet. - required: true - schema: - type: string - example: "dave" + $ref: "components.yaml#/components/schemas/Error" diff --git a/examples/helloworld_async/spec/swagger.yaml b/examples/helloworld_async/spec/swagger.yaml index 948e0418b..0a88619fd 100644 --- a/examples/helloworld_async/spec/swagger.yaml +++ b/examples/helloworld_async/spec/swagger.yaml @@ -1,25 +1,36 @@ swagger: "2.0" info: - title: Hello World + title: "{{title}}" version: "1.0" + basePath: /swagger paths: - /greeting/{name}: - post: - summary: Generate greeting - description: Generates a greeting message. - operationId: hello.post_greeting + /pets: + get: + summary: List all pets responses: '200': - description: greeting response + description: A paged array of pets + schema: + type: array + items: + $ref: 'definitions.yaml#/definitions/Pets' + default: + description: Unexpected Error + schema: + $ref: 'definitions.yaml#/definitions/Error' + + '/pets/{id}': + get: + summary: Info for a specific pet + responses: + '200': + description: Expected response to a valid request + schema: + $ref: 'definitions.yaml#/definitions/Pet' + default: + description: Unexpected Error schema: - type: string - example: "hello dave!" - parameters: - - name: name - in: path - description: Name of the person to greet. - required: true - type: string + $ref: 'definitions.yaml#/definitions/Error' diff --git a/tests/test_mock.py b/tests/test_mock.py index 2b0492925..d7b9e0310 100644 --- a/tests/test_mock.py +++ b/tests/test_mock.py @@ -1,3 +1,4 @@ +from connexion.middleware.security import SecurityOperation from connexion.mock import MockResolver from connexion.operations import OpenAPIOperation, Swagger2Operation @@ -321,3 +322,23 @@ def test_mock_resolver_notimplemented(): "No example response or response schema defined.", 418, ) + + +def test_mock_resolver_multiple_resolves(): + resolver = MockResolver(mock_all=True) + + responses = {"default": {"examples": {"application/json": {"foo": "bar"}}}} + + operation = SecurityOperation( + method="GET", + path="endpoint", + path_parameters=[], + operation={"responses": responses}, + app_produces=["application/json"], + app_consumes=["application/json"], + definitions={}, + resolver=resolver, + ) + + assert resolver.resolve(operation).operation_id == "mock-1" + assert resolver.resolve(operation).operation_id == "mock-1"