Skip to content

Commit 26b0bf9

Browse files
authored
Merge pull request #29 from johmau/add_components_schemas_parsing
feat: add #/components/schemas parsing to retrieve explicit schema
2 parents 82b51c1 + a083f0a commit 26b0bf9

File tree

6 files changed

+133
-4
lines changed

6 files changed

+133
-4
lines changed

src/openapi_parser/builders/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .path import PathBuilder
1313
from .oauth_flow import OAuthFlowBuilder
1414
from .security import SecurityBuilder
15+
from .schemas import SchemasBuilder
1516

1617
__all__ = [
1718
"InfoBuilder",
@@ -28,4 +29,5 @@
2829
"PathBuilder",
2930
"OAuthFlowBuilder",
3031
"SecurityBuilder",
32+
"SchemasBuilder",
3133
]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import logging
2+
3+
from ..specification import Schema
4+
from . import SchemaFactory
5+
6+
7+
logger = logging.getLogger(__name__)
8+
9+
class SchemasBuilder:
10+
schema_factory: SchemaFactory
11+
12+
def __init__(self, schema_factory: SchemaFactory) -> None:
13+
self.schema_factory = schema_factory
14+
15+
def build_collection(self, schemas: dict) -> dict[str, Schema]:
16+
logger.debug(f"Schemas parsing: {schemas.keys()}")
17+
18+
return {
19+
key : self.schema_factory.create(value)
20+
for key, value in schemas.items()
21+
}

src/openapi_parser/parser.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,23 @@ class Parser:
1616
external_doc_builder: ExternalDocBuilder
1717
path_builder: PathBuilder
1818
security_builder: SecurityBuilder
19+
schemas_builder: SchemasBuilder
1920

2021
def __init__(self,
2122
info_builder: InfoBuilder,
2223
server_builder: ServerBuilder,
2324
tags_builder: TagBuilder,
2425
external_doc_builder: ExternalDocBuilder,
2526
path_builder: PathBuilder,
26-
security_builder: SecurityBuilder) -> None:
27+
security_builder: SecurityBuilder,
28+
schemas_builder: SchemasBuilder) -> None:
2729
self.info_builder = info_builder
2830
self.server_builder = server_builder
2931
self.tag_builder = tags_builder
3032
self.external_doc_builder = external_doc_builder
3133
self.path_builder = path_builder
3234
self.security_builder = security_builder
35+
self.schemas_builder = schemas_builder
3336

3437
def load_specification(self, data: dict) -> Specification:
3538
"""Load OpenAPI Specification object from a file or a remote URI.
@@ -67,6 +70,9 @@ def load_specification(self, data: dict) -> Specification:
6770
if data.get('components') and data['components'].get('securitySchemes'):
6871
attrs["security_schemas"] = self.security_builder.build_collection(data['components']['securitySchemes'])
6972

73+
if data.get('components') and data['components'].get('schemas'):
74+
attrs["schemas"] = self.schemas_builder.build_collection(data['components']['schemas'])
75+
7076
logger.debug("Specification parsed successfully")
7177

7278
return Specification(**attrs)
@@ -83,6 +89,7 @@ def _create_parser() -> Parser:
8389
content_builder = ContentBuilder(schema_factory)
8490
header_builder = HeaderBuilder(schema_factory)
8591
parameter_builder = ParameterBuilder(schema_factory)
92+
schemas_builder = SchemasBuilder(schema_factory)
8693
response_builder = ResponseBuilder(content_builder, header_builder)
8794
request_builder = RequestBuilder(content_builder)
8895
operation_builder = OperationBuilder(response_builder,
@@ -98,7 +105,8 @@ def _create_parser() -> Parser:
98105
tag_builder,
99106
external_doc_builder,
100107
path_builder,
101-
security_builder)
108+
security_builder,
109+
schemas_builder)
102110

103111

104112
def parse(uri: str) -> Specification:

src/openapi_parser/specification.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,5 +250,6 @@ class Specification:
250250
tags: list[Tag] = field(default_factory=list)
251251
security_schemas: dict[str, Security] = field(default_factory=dict)
252252
security: list[dict[str, Any]] = field(default_factory=list)
253+
schemas: dict[str, Schema] = field(default_factory=dict)
253254
external_docs: Optional[ExternalDoc] = None
254255
paths: list[Path] = field(default_factory=list)

tests/openapi_fixture.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,100 @@ def create_specification() -> Specification:
157157
),
158158
}
159159

160+
schemas = {
161+
"BadRequestError" : Object(
162+
type=DataType.OBJECT,
163+
required=["code", "error"],
164+
properties=[
165+
Property(
166+
name="code",
167+
schema=Integer(
168+
type=DataType.INTEGER,
169+
example=1044,
170+
description="Internal error code",
171+
)
172+
),
173+
Property(
174+
name="error",
175+
schema=String(
176+
type=DataType.STRING,
177+
example="Invalid user id value",
178+
description="Error details",
179+
)
180+
),
181+
],
182+
),
183+
"InternalServerError": Object(
184+
type=DataType.OBJECT,
185+
required=["code", "error"],
186+
properties=[
187+
Property(
188+
name="code",
189+
schema=Integer(
190+
type=DataType.INTEGER,
191+
example=1,
192+
description="Internal error code",
193+
)
194+
),
195+
Property(
196+
name="error",
197+
schema=String(
198+
type=DataType.STRING,
199+
example="Unexpected server error",
200+
description="Error details",
201+
)
202+
),
203+
],
204+
),
205+
"UUIDObject": Object(
206+
type=DataType.OBJECT,
207+
required=["uuid"],
208+
properties=[
209+
Property(
210+
name="uuid",
211+
schema=String(
212+
type=DataType.STRING,
213+
format=StringFormat.UUID,
214+
example="12345678-1234-5678-1234-567812345678",
215+
description="Unique object id",
216+
)
217+
),
218+
],
219+
),
220+
"User": Object(
221+
type=DataType.OBJECT,
222+
required=["uuid","login", "email"],
223+
properties=[
224+
Property(
225+
name="uuid",
226+
schema=String(
227+
type=DataType.STRING,
228+
format=StringFormat.UUID,
229+
example="12345678-1234-5678-1234-567812345678",
230+
description="Unique object id",
231+
)
232+
),
233+
Property(
234+
name="login",
235+
schema=String(
236+
type=DataType.STRING,
237+
example="super-admin",
238+
description="User login or nickname",
239+
)
240+
),
241+
Property(
242+
name="email",
243+
schema=String(
244+
type=DataType.STRING,
245+
format=StringFormat.EMAIL,
246+
example="user@mail.com",
247+
description="User E-mail address",
248+
)
249+
),
250+
],
251+
)
252+
}
253+
160254
security = [
161255
{"Basic": []}
162256
]
@@ -300,4 +394,5 @@ def create_specification() -> Specification:
300394
tags=tag_list,
301395
paths=path_list,
302396
security_schemas=security_schemes,
303-
security=security)
397+
security=security,
398+
schemas=schemas)

tests/test_parser.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,15 @@ def test_load_specification(swagger_specification: Specification) -> None:
4343
external_doc_builder = _create_builder_mock(swagger_specification.external_docs)
4444
path_builder = _create_list_builder_mock(swagger_specification.paths)
4545
security_builder = _create_collection_builder_mock(swagger_specification.security_schemas)
46+
schemas_builder = _create_collection_builder_mock(swagger_specification.schemas)
4647

4748
parser = Parser(info_builder,
4849
server_list_builder,
4950
tag_list_builder,
5051
external_doc_builder,
5152
path_builder,
52-
security_builder)
53+
security_builder,
54+
schemas_builder)
5355

5456
swagger_json = OpenAPIResolver(SWAGGER_JSON_FILEPATH).resolve()
5557

0 commit comments

Comments
 (0)