diff --git a/connexion/decorators/response.py b/connexion/decorators/response.py index c278b6715..f1a9bcefc 100644 --- a/connexion/decorators/response.py +++ b/connexion/decorators/response.py @@ -55,9 +55,10 @@ def validate_response(self, data, status_code, headers, url): raise NonConformingResponseBody(message=str(e)) if response_definition and response_definition.get("headers"): - response_definition_header_keys = response_definition.get("headers").keys() - header_keys = headers.keys() - missing_keys = response_definition_header_keys - header_keys + required_header_keys = {k for (k, v) in response_definition.get("headers").items() + if v.get("required", False)} + header_keys = set(headers.keys()) + missing_keys = required_header_keys - header_keys if missing_keys: pretty_list = ', '.join(missing_keys) msg = ("Keys in header don't match response specification. " diff --git a/tests/api/test_headers.py b/tests/api/test_headers.py index 0b6c88c75..0eb64ed63 100644 --- a/tests/api/test_headers.py +++ b/tests/api/test_headers.py @@ -17,8 +17,8 @@ def test_headers_produces(simple_app): assert response.headers["Location"] == "http://localhost/my/uri" -def test_header_not_returned(simple_app): - app_client = simple_app.app.test_client() +def test_header_not_returned(simple_openapi_app): + app_client = simple_openapi_app.app.test_client() response = app_client.post('/v1.0/goodday/noheader', data={}) # type: flask.Response assert response.status_code == 500 # view_func has not returned what was promised in spec @@ -42,3 +42,10 @@ def test_no_content_object_and_have_headers(simple_app): resp = app_client.get('/v1.0/test-204-with-headers-nocontent-obj') assert resp.status_code == 204 assert 'X-Something' in resp.headers + + +def test_optional_header(simple_openapi_app): + app_client = simple_openapi_app.app.test_client() + resp = app_client.get('/v1.0/test-optional-headers') + assert resp.status_code == 200 + assert 'X-Optional-Header' not in resp.headers diff --git a/tests/fakeapi/hello/__init__.py b/tests/fakeapi/hello/__init__.py index 26ef42e74..997c2ac0c 100644 --- a/tests/fakeapi/hello/__init__.py +++ b/tests/fakeapi/hello/__init__.py @@ -601,3 +601,7 @@ def get_date(): def get_uuid(): return {'value': uuid.UUID(hex='e7ff66d0-3ec2-4c4e-bed0-6e4723c24c51')} + + +def test_optional_headers(): + return {}, 200 diff --git a/tests/fixtures/simple/openapi.yaml b/tests/fixtures/simple/openapi.yaml index 80a3bf4fc..a448830c6 100644 --- a/tests/fixtures/simple/openapi.yaml +++ b/tests/fixtures/simple/openapi.yaml @@ -690,6 +690,7 @@ paths: description: The URI of the created resource schema: type: string + required: true content: 'application/json': schema: @@ -714,6 +715,7 @@ paths: description: The URI of the created resource schema: type: string + required: true content: 'application/json': schema: @@ -731,6 +733,7 @@ paths: description: The URI of the created resource schema: type: string + required: true content: text/plain: schema: @@ -1140,6 +1143,22 @@ paths: application/json: schema: type: object + /test-optional-headers: + get: + operationId: fakeapi.hello.test_optional_headers + responses: + '200': + description: Some object response + content: + application/json: + schema: + type: object + headers: + X-Optional-Header: + description: Optional header + schema: + type: string + required: false servers: - url: http://localhost:{port}/{basePath} diff --git a/tests/fixtures/simple/swagger.yaml b/tests/fixtures/simple/swagger.yaml index 32d680e60..de3db771e 100644 --- a/tests/fixtures/simple/swagger.yaml +++ b/tests/fixtures/simple/swagger.yaml @@ -556,21 +556,6 @@ paths: required: true type: string - /goodday/noheader: - post: - summary: Generate good day greeting - description: Generates a good day message. - operationId: fakeapi.hello.post_goodday_no_header - responses: - 201: - description: gooday response - headers: - Location: - type: string - description: The URI of the created resource - schema: - type: object - /goodevening/{name}: post: summary: Generate good evening