From 9cb292dcb6e14c52b91321bab05b3c585745b32d Mon Sep 17 00:00:00 2001
From: Philippe Auriach
Date: Mon, 25 Sep 2023 17:02:03 +0200
Subject: [PATCH 1/3] Add response content_types
---
chalice_spec/docs.py | 49 +++++++++++++++++++++++--------------------
tests/test_chalice.py | 11 ++++++++--
2 files changed, 35 insertions(+), 25 deletions(-)
diff --git a/chalice_spec/docs.py b/chalice_spec/docs.py
index 50d1c3e..9055adb 100644
--- a/chalice_spec/docs.py
+++ b/chalice_spec/docs.py
@@ -6,6 +6,7 @@
DEFAULT_DESCRIPTION = "Success"
DEFAULT_CODE = 200
+DEFAULT_CONTENT_TYPE = "application/json"
class Response:
@@ -15,10 +16,11 @@ class Response:
and an optional description.
"""
- def __init__(self, model: type, code: int = 200, description: str = "Success"):
+ def __init__(self, model: type, code: int = 200, description: str = "Success", content_type: str = DEFAULT_CONTENT_TYPE):
self.model = model
self.code = code
self.description = description
+ self.content_type = content_type
class Operation:
@@ -59,19 +61,19 @@ def __init__(
def _populate_response(self, response: Union[Response, type]):
if isinstance(response, Response):
# If this is a Response object, we can track it as-is.
- self.responses = {response.code: response}
+ self.responses = {response.code: {DEFAULT_CONTENT_TYPE: response}}
else:
# If not, we will use sensible defaults
- self.responses = {DEFAULT_CODE: Response(model=response)}
+ self.responses = {DEFAULT_CODE: {DEFAULT_CONTENT_TYPE: Response(model=response)}}
def _populate_responses(self, responses: List[Response]):
self.responses = {}
for response in responses:
- if response.code in self.responses:
- raise TypeError(
- "You must only specify one response per HTTP status code"
- )
- self.responses[response.code] = response
+ if response.code not in self.responses:
+ self.responses[response.code] = {}
+ if response.content_type in self.responses[response.code]:
+ raise TypeError(f"Multiple responses defined for {response.code} — {response.content_type}")
+ self.responses[response.code][response.content_type] = response
Method = Union[Type[BaseModel], Operation]
@@ -139,7 +141,7 @@ def _build_operation_from_operation(
if method.content_types
else content_types[0]
if content_types
- else "application/json"
+ else DEFAULT_CONTENT_TYPE
)
operation["requestBody"] = {
"content": {
@@ -152,21 +154,22 @@ def _build_operation_from_operation(
if method.responses:
responses = {}
- for code, response in method.responses.items():
- if response.model.__name__ not in spec.components.schemas:
- spec.components.schema(
- response.model.__name__,
- model=response.model,
- spec=spec,
- )
- responses[code] = {
- "description": response.description,
- "content": {
- "application/json": {
- "schema": response.model.__name__,
+ for code, response_contents in method.responses.items():
+ for content_type, response in response_contents.items():
+ if response.model.__name__ not in spec.components.schemas:
+ spec.components.schema(
+ response.model.__name__,
+ model=response.model,
+ spec=spec,
+ )
+ if code not in responses:
+ responses[code] = {
+ "description": response.description,
+ "content": {},
}
- },
- }
+ responses[code]['content'][content_type] = {
+ "schema": response.model.__name__
+ }
operation["responses"] = responses
diff --git a/tests/test_chalice.py b/tests/test_chalice.py
index bf0de42..33edcdd 100644
--- a/tests/test_chalice.py
+++ b/tests/test_chalice.py
@@ -421,16 +421,18 @@ def get_post():
},
}
-
# Test 9: different content_types
def test_content_types():
app, spec = setup_test()
+ with pytest.raises(TypeError):
+ Op(responses=[Resp(model=TestSchema), Resp(model=TestSchema)])
+
@app.route(
"/posts",
methods=["POST"],
content_types=["multipart/form-data"],
- docs=Docs(request=TestSchema, response=AnotherSchema),
+ docs=Docs(request=TestSchema, responses=[Resp(model=AnotherSchema, content_type="application/json"), Resp(model=AnotherSchema, content_type="application/xml")]),
)
def get_post():
pass
@@ -454,6 +456,11 @@ def get_post():
"schema": {
"$ref": "#/components/schemas/AnotherSchema"
}
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/AnotherSchema"
+ }
}
},
}
From ee3559a8d00d2243abdbbfcdd8c6730410dd5252 Mon Sep 17 00:00:00 2001
From: Philippe Auriach
Date: Mon, 25 Sep 2023 17:13:50 +0200
Subject: [PATCH 2/3] format
---
chalice_spec/docs.py | 16 +++++++++++++---
tests/test_chalice.py | 8 +++++++-
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/chalice_spec/docs.py b/chalice_spec/docs.py
index 9055adb..7b455ca 100644
--- a/chalice_spec/docs.py
+++ b/chalice_spec/docs.py
@@ -16,7 +16,13 @@ class Response:
and an optional description.
"""
- def __init__(self, model: type, code: int = 200, description: str = "Success", content_type: str = DEFAULT_CONTENT_TYPE):
+ def __init__(
+ self,
+ model: type,
+ code: int = 200,
+ description: str = "Success",
+ content_type: str = DEFAULT_CONTENT_TYPE
+ ):
self.model = model
self.code = code
self.description = description
@@ -64,7 +70,9 @@ def _populate_response(self, response: Union[Response, type]):
self.responses = {response.code: {DEFAULT_CONTENT_TYPE: response}}
else:
# If not, we will use sensible defaults
- self.responses = {DEFAULT_CODE: {DEFAULT_CONTENT_TYPE: Response(model=response)}}
+ self.responses = {
+ DEFAULT_CODE: {DEFAULT_CONTENT_TYPE: Response(model=response)}
+ }
def _populate_responses(self, responses: List[Response]):
self.responses = {}
@@ -72,7 +80,9 @@ def _populate_responses(self, responses: List[Response]):
if response.code not in self.responses:
self.responses[response.code] = {}
if response.content_type in self.responses[response.code]:
- raise TypeError(f"Multiple responses defined for {response.code} — {response.content_type}")
+ raise TypeError(
+ f"Multiple responses defined for {response.code} — {response.content_type}"
+ )
self.responses[response.code][response.content_type] = response
diff --git a/tests/test_chalice.py b/tests/test_chalice.py
index 33edcdd..358a6a5 100644
--- a/tests/test_chalice.py
+++ b/tests/test_chalice.py
@@ -432,7 +432,13 @@ def test_content_types():
"/posts",
methods=["POST"],
content_types=["multipart/form-data"],
- docs=Docs(request=TestSchema, responses=[Resp(model=AnotherSchema, content_type="application/json"), Resp(model=AnotherSchema, content_type="application/xml")]),
+ docs=Docs(
+ request=TestSchema,
+ responses=[
+ Resp(model=AnotherSchema, content_type="application/json"),
+ Resp(model=AnotherSchema, content_type="application/xml")
+ ],
+ ),
)
def get_post():
pass
From 44ceaf3fa2cf283d2f5d7aba997145a2002dea47 Mon Sep 17 00:00:00 2001
From: Philippe Auriach
Date: Mon, 25 Sep 2023 17:16:50 +0200
Subject: [PATCH 3/3] black
---
chalice_spec/docs.py | 12 ++++++------
tests/test_chalice.py | 5 +++--
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/chalice_spec/docs.py b/chalice_spec/docs.py
index 7b455ca..a856708 100644
--- a/chalice_spec/docs.py
+++ b/chalice_spec/docs.py
@@ -17,11 +17,11 @@ class Response:
"""
def __init__(
- self,
- model: type,
- code: int = 200,
- description: str = "Success",
- content_type: str = DEFAULT_CONTENT_TYPE
+ self,
+ model: type,
+ code: int = 200,
+ description: str = "Success",
+ content_type: str = DEFAULT_CONTENT_TYPE,
):
self.model = model
self.code = code
@@ -177,7 +177,7 @@ def _build_operation_from_operation(
"description": response.description,
"content": {},
}
- responses[code]['content'][content_type] = {
+ responses[code]["content"][content_type] = {
"schema": response.model.__name__
}
diff --git a/tests/test_chalice.py b/tests/test_chalice.py
index 358a6a5..db20b5a 100644
--- a/tests/test_chalice.py
+++ b/tests/test_chalice.py
@@ -421,6 +421,7 @@ def get_post():
},
}
+
# Test 9: different content_types
def test_content_types():
app, spec = setup_test()
@@ -436,7 +437,7 @@ def test_content_types():
request=TestSchema,
responses=[
Resp(model=AnotherSchema, content_type="application/json"),
- Resp(model=AnotherSchema, content_type="application/xml")
+ Resp(model=AnotherSchema, content_type="application/xml"),
],
),
)
@@ -467,7 +468,7 @@ def get_post():
"schema": {
"$ref": "#/components/schemas/AnotherSchema"
}
- }
+ },
},
}
},