Skip to content

Commit

Permalink
openapi - schema ref nesting
Browse files Browse the repository at this point in the history
resolve referenced nested references while taking care of self references
  • Loading branch information
commonism committed Dec 7, 2023
1 parent 0d88a26 commit 2bf3d2b
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 1 deletion.
3 changes: 3 additions & 0 deletions aiopenapi3/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ def resolve_jp(self, jp):
node = node[int(part)]
elif isinstance(node, ObjectBase):
part = Model.nameof(part)
if isinstance(node, ReferenceBase) and node._target is None:
"""unresolved reference - requires resolving the reference first"""
return node
if not hasattr(node, part):
raise ReferenceResolutionError(f"Invalid path {path[:idx]} in Reference")
node = getattr(node, part)
Expand Down
13 changes: 12 additions & 1 deletion aiopenapi3/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,18 @@ def resolve_jr(self, root: RootBase, obj, value: Reference):
root = self._documents[url]

try:
return root.resolve_jp(jp)
while True:
r = root.resolve_jp(jp)
if isinstance(r, ReferenceBase):
"""
returned node is a unresolved reference
resolve & retry
"""
r._target = root.resolve_jp(r.ref)
if isinstance(r._target, ReferenceBase) and r.ref == r._target.ref:
return r
continue
return r
except ReferenceResolutionError as e:
# add metadata to the error
e.element = obj
Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,3 +488,8 @@ def with_paths_server_variables(openapi_version):
@pytest.fixture
def with_paths_response_error():
yield _get_parsed_yaml("paths-response-error.yaml")


@pytest.fixture
def with_schema_ref_nesting():
yield _get_parsed_yaml("schema-ref-nesting.yaml")
54 changes: 54 additions & 0 deletions tests/fixtures/schema-ref-nesting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
openapi: 3.0.0
info:
title: OpenStreetMap circular refs
description: This is the editing API for OpenStreetMap.
version: '0.6'
servers:
- url: '/'
paths:
/api/0.6/map:
get:
summary: Retrieves map data by the given bounding box.
description: |
The operation returns:
operationId: getMapDataByBoundingBox
responses:
'200':
description: okay
content:
application/json:
schema:
type: object
properties:
elements:
type: array
items:
oneOf:
- $ref: '#/components/schemas/Node'
components:
schemas:
Node:
allOf:
- $ref: '#/components/schemas/Way/allOf/0'
Way:
allOf:
- type: object
properties:
type:
type: string
Relation:
allOf:
- type: object
properties:
members:
type: array
items:
type: object
properties:
type:
$ref: '#/paths/~1api~10.6~1map/get/responses/200/content/application~1json/schema/properties/elements/items/oneOf/0/allOf/0/properties/type'
required:
- members
externalDocs:
description: Find more information on the OSM wiki
url: 'https://wiki.openstreetmap.org/'
5 changes: 5 additions & 0 deletions tests/schema_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,3 +465,8 @@ def test_schema_pathitems(httpx_mock, with_schema_pathitems):
def test_schema_baseurl_v20(with_schema_baseurl_v20):
api = OpenAPI("/", with_schema_baseurl_v20, session_factory=httpx.Client)
assert api.url == yarl.URL("https://api.example.com:81/v1")


def test_schema_ref_nesting(with_schema_ref_nesting):
for i in range(10):
OpenAPI("/", with_schema_ref_nesting)

0 comments on commit 2bf3d2b

Please sign in to comment.