Skip to content

Commit 1b1d150

Browse files
committed
feat: Support any content type ending in +json [#706]. Thanks @XioNoX and @mtovt!
1 parent e7a4e71 commit 1b1d150

File tree

3 files changed

+24
-14
lines changed

3 files changed

+24
-14
lines changed

openapi_python_client/parser/openapi.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,12 @@ def parse_request_json_body(
176176
*, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config
177177
) -> Tuple[Union[Property, PropertyError, None], Schemas]:
178178
"""Return json_body"""
179-
body_content = body.content
180-
json_body = body_content.get("application/json")
179+
json_body = None
180+
for content_type, schema in body.content.items():
181+
if content_type == "application/json" or content_type.endswith("+json"):
182+
json_body = schema
183+
break
184+
181185
if json_body is not None and json_body.media_type_schema is not None:
182186
return property_from_data(
183187
name="json_body",

openapi_python_client/parser/responses.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@ class Response:
2121
source: str
2222

2323

24-
_SOURCE_BY_CONTENT_TYPE = {
25-
"application/json": "response.json()",
26-
"application/vnd.api+json": "response.json()",
27-
"application/octet-stream": "response.content",
28-
"text/html": "response.text",
29-
}
24+
def _source_by_content_type(content_type: str) -> Optional[str]:
25+
known_content_types = {
26+
"application/json": "response.json()",
27+
"application/octet-stream": "response.content",
28+
"text/html": "response.text",
29+
}
30+
source = known_content_types.get(content_type)
31+
if source is None and content_type.endswith("+json"):
32+
# Implements https://www.rfc-editor.org/rfc/rfc6838#section-4.2.8 for the +json suffix
33+
source = "response.json()"
34+
return source
3035

3136

3237
def empty_response(
@@ -75,8 +80,8 @@ def response_from_data(
7580
)
7681

7782
for content_type, media_type in content.items():
78-
if content_type in _SOURCE_BY_CONTENT_TYPE:
79-
source = _SOURCE_BY_CONTENT_TYPE[content_type]
83+
source = _source_by_content_type(content_type)
84+
if source is not None:
8085
schema_data = media_type.media_type_schema
8186
break
8287
else:

tests/test_parser/test_openapi.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,14 @@ def test_parse_multipart_body_no_data(self):
246246

247247
assert prop is None
248248

249-
def test_parse_request_json_body(self, mocker):
249+
@pytest.mark.parametrize(
250+
"content_type", ("application/json", "application/vnd.api+json", "application/yang-data+json")
251+
)
252+
def test_parse_request_json_body(self, mocker, content_type):
250253
from openapi_python_client.parser.openapi import Endpoint, Schemas
251254

252255
schema = mocker.MagicMock()
253-
body = oai.RequestBody.construct(
254-
content={"application/json": oai.MediaType.construct(media_type_schema=schema)}
255-
)
256+
body = oai.RequestBody.construct(content={content_type: oai.MediaType.construct(media_type_schema=schema)})
256257
property_from_data = mocker.patch(f"{MODULE_NAME}.property_from_data")
257258
schemas = Schemas()
258259
config = MagicMock()

0 commit comments

Comments
 (0)