Skip to content

Commit fccff53

Browse files
authored
Merge pull request #177 from p1c2u/fix/responses-schema-validation-fix
Responses schema validation
2 parents ba1f596 + 14ebd85 commit fccff53

File tree

3 files changed

+185
-1
lines changed

3 files changed

+185
-1
lines changed

openapi_spec_validator/validation/validators.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ def _iter_operation_errors(
140140
)
141141
self.operation_ids_registry.append(operation_id)
142142

143+
if "responses" in operation:
144+
responses = operation / "responses"
145+
yield from self._iter_responses_errors(responses)
146+
143147
names = []
144148

145149
parameters = None
@@ -161,6 +165,35 @@ def _iter_operation_errors(
161165
)
162166
return
163167

168+
def _iter_responses_errors(
169+
self, responses: Spec
170+
) -> Iterator[ValidationError]:
171+
for response_code, response in responses.items():
172+
yield from self._iter_response_errors(response_code, response)
173+
174+
def _iter_response_errors(
175+
self, response_code: str, response: Spec
176+
) -> Iterator[ValidationError]:
177+
# openapi 2
178+
if "schema" in response:
179+
schema = response / "schema"
180+
yield from self._iter_schema_errors(schema)
181+
# openapi 3
182+
if "content" in response:
183+
content = response / "content"
184+
yield from self._iter_content_errors(content)
185+
186+
def _iter_content_errors(self, content: Spec) -> Iterator[ValidationError]:
187+
for mimetype, media_type in content.items():
188+
yield from self._iter_media_type_errors(mimetype, media_type)
189+
190+
def _iter_media_type_errors(
191+
self, mimetype: str, media_type: Spec
192+
) -> Iterator[ValidationError]:
193+
if "schema" in media_type:
194+
schema = media_type / "schema"
195+
yield from self._iter_schema_errors(schema)
196+
164197
def _get_path_param_names(self, params: Spec) -> Iterator[str]:
165198
for param in params:
166199
if param["in"] == "path":
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
swagger: "2.0"
2+
info:
3+
version: 1.0.0
4+
title: Swagger Petstore
5+
license:
6+
name: MIT
7+
host: petstore.swagger.io
8+
basePath: /v1
9+
schemes:
10+
- http
11+
consumes:
12+
- application/json
13+
produces:
14+
- application/json
15+
paths:
16+
/pets:
17+
get:
18+
summary: List all pets
19+
operationId: listPets
20+
tags:
21+
- pets
22+
parameters:
23+
- name: limit
24+
in: query
25+
description: How many items to return at one time (max 100)
26+
required: false
27+
type: integer
28+
format: int32
29+
responses:
30+
200:
31+
description: A paged array of pets
32+
headers:
33+
x-next:
34+
type: string
35+
description: A link to the next page of responses
36+
schema:
37+
$ref: 'definitions/Pets'
38+
default:
39+
description: unexpected error
40+
schema:
41+
$ref: '#/definitions/'
42+
post:
43+
summary: Create a pet
44+
operationId: createPets
45+
tags:
46+
- pets
47+
responses:
48+
'201':
49+
description: Null response
50+
default:
51+
description: unexpected error
52+
schema:
53+
$ref: '#/definitions/Error'
54+
/pets/{petId}:
55+
get:
56+
summary: Info for a specific pet
57+
operationId: showPetById
58+
tags:
59+
- pets
60+
parameters:
61+
- name: petId
62+
in: path
63+
required: true
64+
description: The id of the pet to retrieve
65+
type: string
66+
responses:
67+
'200':
68+
description: Expected response to a valid request
69+
schema:
70+
$ref: '#/definitions/Pets'
71+
default:
72+
description: unexpected error
73+
schema:
74+
$ref: '#/definitions/Error'
75+
definitions:
76+
Pet:
77+
required:
78+
- id
79+
- name
80+
properties:
81+
id:
82+
type: integer
83+
format: int64
84+
name:
85+
type: string
86+
tag:
87+
type: string
88+
Pets:
89+
type: array
90+
items:
91+
$ref: '#/definitions/Pet'
92+
Error:
93+
required:
94+
- code
95+
- message
96+
properties:
97+
code:
98+
type: integer
99+
format: int32
100+
message:
101+
type: string

tests/integration/validation/test_validators.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,58 @@
11
import pytest
2+
from jsonschema.exceptions import RefResolutionError
23

34
from openapi_spec_validator.validation.exceptions import OpenAPIValidationError
45

56

7+
class TestLocalOpenAPIv2Validator:
8+
9+
LOCAL_SOURCE_DIRECTORY = "data/v2.0/"
10+
11+
def local_test_suite_file_path(self, test_file):
12+
return f"{self.LOCAL_SOURCE_DIRECTORY}{test_file}"
13+
14+
@pytest.mark.parametrize(
15+
"spec_file",
16+
[
17+
"petstore.yaml",
18+
],
19+
)
20+
def test_valid(self, factory, validator_v2, spec_file):
21+
spec_path = self.local_test_suite_file_path(spec_file)
22+
spec = factory.spec_from_file(spec_path)
23+
spec_url = factory.spec_file_url(spec_path)
24+
25+
return validator_v2.validate(spec, spec_url=spec_url)
26+
27+
@pytest.mark.parametrize(
28+
"spec_file",
29+
[
30+
"empty.yaml",
31+
],
32+
)
33+
def test_validation_failed(self, factory, validator_v2, spec_file):
34+
spec_path = self.local_test_suite_file_path(spec_file)
35+
spec = factory.spec_from_file(spec_path)
36+
spec_url = factory.spec_file_url(spec_path)
37+
38+
with pytest.raises(OpenAPIValidationError):
39+
validator_v2.validate(spec, spec_url=spec_url)
40+
41+
@pytest.mark.parametrize(
42+
"spec_file",
43+
[
44+
"missing-reference.yaml",
45+
],
46+
)
47+
def test_ref_failed(self, factory, validator_v2, spec_file):
48+
spec_path = self.local_test_suite_file_path(spec_file)
49+
spec = factory.spec_from_file(spec_path)
50+
spec_url = factory.spec_file_url(spec_path)
51+
52+
with pytest.raises(RefResolutionError):
53+
validator_v2.validate(spec, spec_url=spec_url)
54+
55+
656
class TestLocalOpenAPIv30Validator:
757

858
LOCAL_SOURCE_DIRECTORY = "data/v3.0/"
@@ -31,7 +81,7 @@ def test_valid(self, factory, validator_v30, spec_file):
3181
"empty.yaml",
3282
],
3383
)
34-
def test_falied(self, factory, validator_v30, spec_file):
84+
def test_failed(self, factory, validator_v30, spec_file):
3585
spec_path = self.local_test_suite_file_path(spec_file)
3686
spec = factory.spec_from_file(spec_path)
3787
spec_url = factory.spec_file_url(spec_path)

0 commit comments

Comments
 (0)