Skip to content

Commit 7d41436

Browse files
committed
Merge extra_responses to responses and deprecate extra_responses
1 parent f4e4b1b commit 7d41436

File tree

11 files changed

+86
-61
lines changed

11 files changed

+86
-61
lines changed

examples/api_blueprint_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def get_book():
5555
return {"code": 0, "message": "ok"}
5656

5757

58-
@api.post('/book', extra_responses={"200": {"content": {"text/csv": {"schema": {"type": "string"}}}}})
58+
@api.post('/book', responses={"200": {"content": {"text/csv": {"schema": {"type": "string"}}}}})
5959
def create_book(body: BookBody):
6060
assert body.age == 3
6161
return {"code": 0, "message": "ok"}

examples/response_demo.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from flask_openapi3 import Info
1212
from flask_openapi3 import OpenAPI, APIBlueprint
1313

14-
app = OpenAPI(__name__, info=Info(title="Hello API", version="1.0.0"), )
14+
app = OpenAPI(__name__, info=Info(title="Hello API", version="1.0.0"))
1515

1616
bp = APIBlueprint("Hello BP", __name__)
1717

@@ -43,7 +43,8 @@ class Config:
4343
}
4444

4545

46-
@bp.get("/hello/<string:name>", responses={"200": Message})
46+
@bp.get("/hello/<string:name>",
47+
responses={"200": Message, "201": {"content": {"text/csv": {"schema": {"type": "string"}}}}})
4748
def hello(path: HelloPath):
4849
message = {"message": f"""Hello {path.name}!"""}
4950

examples/rest_demo.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,7 @@ class BookResponse(BaseModel):
9595
external_docs=ExternalDocumentation(
9696
url="https://www.openapis.org/",
9797
description="Something great got better, get excited!"),
98-
9998
responses={"200": BookResponse},
100-
extra_responses={"200": {"content": {"text/csv": {"schema": {"type": "string"}}}}},
10199
security=security,
102100
servers=[Server(url="https://www.openapis.org/", description="openapi")]
103101
)

flask_openapi3/blueprint.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# @Time : 2022/4/1 16:54
44
import re
55
from copy import deepcopy
6-
from typing import Optional, List, Dict, Any, Type, Callable, Tuple
6+
from typing import Optional, List, Dict, Any, Type, Callable, Tuple, Union
77

88
from flask import Blueprint
99
from pydantic import BaseModel
@@ -25,7 +25,7 @@ def __init__(
2525
*,
2626
abp_tags: Optional[List[Tag]] = None,
2727
abp_security: Optional[List[Dict[str, List[str]]]] = None,
28-
abp_responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
28+
abp_responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
2929
doc_ui: bool = True,
3030
operation_id_callback: Callable = get_operation_id_for_path,
3131
**kwargs: Any
@@ -39,7 +39,7 @@ def __init__(
3939
``__name__``. This helps locate the ``root_path`` for the blueprint.
4040
abp_tags: APIBlueprint tags for every api
4141
abp_security: APIBlueprint security for every api
42-
abp_responses: APIBlueprint response model
42+
abp_responses: API responses, should be BaseModel, dict or None.
4343
doc_ui: Add openapi document UI(swagger, rapidoc and redoc). Defaults to True.
4444
operation_id_callback: Callback function for custom operation_id generation.
4545
Receives name (str), path (str) and method (str) parameters.
@@ -92,7 +92,7 @@ def _do_decorator(
9292
operation_id: Optional[str] = None,
9393
extra_form: Optional[ExtraRequestBody] = None,
9494
extra_body: Optional[ExtraRequestBody] = None,
95-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
95+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
9696
extra_responses: Optional[Dict[str, Dict]] = None,
9797
deprecated: Optional[bool] = None,
9898
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -113,7 +113,7 @@ def _do_decorator(
113113
operation_id: Unique string used to identify the operation.
114114
extra_form: Extra information describing the request body(application/form).
115115
extra_body: Extra information describing the request body(application/json).
116-
responses: response's model must be pydantic BaseModel.
116+
responses: API responses, should be BaseModel, dict or None.
117117
extra_responses: Extra information for responses.
118118
deprecated: Declares this operation to be deprecated.
119119
security: A declaration of which security mechanisms can be used for this operation.

flask_openapi3/openapi.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(
3232
info: Optional[Info] = None,
3333
security_schemes: Optional[Dict[str, Union[SecurityScheme, Dict[str, Any]]]] = None,
3434
oauth_config: Optional[OAuthConfig] = None,
35-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
35+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
3636
doc_ui: bool = True,
3737
doc_expansion: str = "list",
3838
doc_prefix: str = "/openapi",
@@ -56,7 +56,7 @@ def __init__(
5656
security_schemes: See https://spec.openapis.org/oas/v3.0.3#security-scheme-object
5757
oauth_config: OAuth 2.0 configuration,
5858
see https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/oauth2.md
59-
responses: OpenAPI response model
59+
responses: API responses, should be BaseModel, dict or None.
6060
doc_ui: Add openapi document UI(swagger and redoc). Defaults to True.
6161
doc_expansion: String=["list"*, "full", "none"].
6262
Controls the default expansion setting for the operations and tags.
@@ -220,7 +220,7 @@ def _do_decorator(
220220
operation_id: Optional[str] = None,
221221
extra_form: Optional[ExtraRequestBody] = None,
222222
extra_body: Optional[ExtraRequestBody] = None,
223-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
223+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
224224
extra_responses: Optional[Dict[str, Dict]] = None,
225225
deprecated: Optional[bool] = None,
226226
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -241,7 +241,7 @@ def _do_decorator(
241241
operation_id: Unique string used to identify the operation.
242242
extra_form: Extra information describing the request body(application/form).
243243
extra_body: Extra information describing the request body(application/json).
244-
responses: response's model must be pydantic BaseModel.
244+
responses: API responses, should be BaseModel, dict or None.
245245
extra_responses: Extra information for responses.
246246
deprecated: Declares this operation to be deprecated.
247247
security: A declaration of which security mechanisms can be used for this operation.

flask_openapi3/scaffold.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import warnings
88
from abc import ABC
99
from functools import wraps
10-
from typing import Callable, List, Optional, Dict, Type, Any, Tuple
10+
from typing import Callable, List, Optional, Dict, Type, Any, Tuple, Union
1111

1212
from flask.scaffold import Scaffold
1313
from flask.wrappers import Response
@@ -48,7 +48,7 @@ def _do_decorator(
4848
operation_id: Optional[str] = None,
4949
extra_form: Optional[ExtraRequestBody] = None,
5050
extra_body: Optional[ExtraRequestBody] = None,
51-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
51+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
5252
extra_responses: Optional[Dict[str, dict]] = None,
5353
deprecated: Optional[bool] = None,
5454
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -146,7 +146,7 @@ def get(
146146
operation_id: Optional[str] = None,
147147
extra_form: Optional[ExtraRequestBody] = None,
148148
extra_body: Optional[ExtraRequestBody] = None,
149-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
149+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
150150
extra_responses: Optional[Dict[str, dict]] = None,
151151
deprecated: Optional[bool] = None,
152152
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -168,7 +168,7 @@ def get(
168168
operation_id: Unique string used to identify the operation.
169169
extra_form: Extra information describing the request body(application/form).
170170
extra_body: Extra information describing the request body(application/json).
171-
responses: response's model must be pydantic BaseModel.
171+
responses: API responses, should be BaseModel, dict or None.
172172
extra_responses: Extra information for responses.
173173
deprecated: Declares this operation to be deprecated.
174174
security: A declaration of which security mechanisms can be used for this operation.
@@ -185,6 +185,10 @@ def get(
185185
warnings.warn(
186186
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
187187
DeprecationWarning)
188+
if extra_responses is not None:
189+
warnings.warn(
190+
"""`extra_responses` will be deprecated in v3.x, please use `responses` instead.""",
191+
DeprecationWarning)
188192

189193
def decorator(func) -> Callable:
190194
header, cookie, path, query, form, body = \
@@ -227,7 +231,7 @@ def post(
227231
operation_id: Optional[str] = None,
228232
extra_form: Optional[ExtraRequestBody] = None,
229233
extra_body: Optional[ExtraRequestBody] = None,
230-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
234+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
231235
extra_responses: Optional[Dict[str, dict]] = None,
232236
deprecated: Optional[bool] = None,
233237
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -249,7 +253,7 @@ def post(
249253
operation_id: Unique string used to identify the operation.
250254
extra_form: Extra information describing the request body(application/form).
251255
extra_body: Extra information describing the request body(application/json).
252-
responses: response's model must be pydantic BaseModel.
256+
responses: API responses, should be BaseModel, dict or None.
253257
extra_responses: Extra information for responses.
254258
deprecated: Declares this operation to be deprecated.
255259
security: A declaration of which security mechanisms can be used for this operation.
@@ -265,6 +269,10 @@ def post(
265269
warnings.warn(
266270
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
267271
DeprecationWarning)
272+
if extra_responses is not None:
273+
warnings.warn(
274+
"""`extra_responses` will be deprecated in v3.x, please use `responses` instead.""",
275+
DeprecationWarning)
268276

269277
def decorator(func) -> Callable:
270278
header, cookie, path, query, form, body = \
@@ -307,7 +315,7 @@ def put(
307315
operation_id: Optional[str] = None,
308316
extra_form: Optional[ExtraRequestBody] = None,
309317
extra_body: Optional[ExtraRequestBody] = None,
310-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
318+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
311319
extra_responses: Optional[Dict[str, dict]] = None,
312320
deprecated: Optional[bool] = None,
313321
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -329,7 +337,7 @@ def put(
329337
operation_id: Unique string used to identify the operation.
330338
extra_form: Extra information describing the request body(application/form).
331339
extra_body: Extra information describing the request body(application/json).
332-
responses: response's model must be pydantic BaseModel.
340+
responses: API responses, should be BaseModel, dict or None.
333341
extra_responses: Extra information for responses.
334342
deprecated: Declares this operation to be deprecated.
335343
security: A declaration of which security mechanisms can be used for this operation.
@@ -345,6 +353,10 @@ def put(
345353
warnings.warn(
346354
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
347355
DeprecationWarning)
356+
if extra_responses is not None:
357+
warnings.warn(
358+
"""`extra_responses` will be deprecated in v3.x, please use `responses` instead.""",
359+
DeprecationWarning)
348360

349361
def decorator(func) -> Callable:
350362
header, cookie, path, query, form, body = \
@@ -387,7 +399,7 @@ def delete(
387399
operation_id: Optional[str] = None,
388400
extra_form: Optional[ExtraRequestBody] = None,
389401
extra_body: Optional[ExtraRequestBody] = None,
390-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
402+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
391403
extra_responses: Optional[Dict[str, dict]] = None,
392404
deprecated: Optional[bool] = None,
393405
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -409,7 +421,7 @@ def delete(
409421
operation_id: Unique string used to identify the operation.
410422
extra_form: Extra information describing the request body(application/form).
411423
extra_body: Extra information describing the request body(application/json).
412-
responses: response's model must be pydantic BaseModel.
424+
responses: API responses, should be BaseModel, dict or None.
413425
extra_responses: Extra information for responses.
414426
deprecated: Declares this operation to be deprecated.
415427
security: A declaration of which security mechanisms can be used for this operation.
@@ -425,6 +437,10 @@ def delete(
425437
warnings.warn(
426438
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
427439
DeprecationWarning)
440+
if extra_responses is not None:
441+
warnings.warn(
442+
"""`extra_responses` will be deprecated in v3.x, please use `responses` instead.""",
443+
DeprecationWarning)
428444

429445
def decorator(func) -> Callable:
430446
header, cookie, path, query, form, body = \
@@ -467,7 +483,7 @@ def patch(
467483
operation_id: Optional[str] = None,
468484
extra_form: Optional[ExtraRequestBody] = None,
469485
extra_body: Optional[ExtraRequestBody] = None,
470-
responses: Optional[Dict[str, Optional[Type[BaseModel]]]] = None,
486+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]] = None,
471487
extra_responses: Optional[Dict[str, dict]] = None,
472488
deprecated: Optional[bool] = None,
473489
security: Optional[List[Dict[str, List[Any]]]] = None,
@@ -489,7 +505,7 @@ def patch(
489505
operation_id: Unique string used to identify the operation.
490506
extra_form: Extra information describing the request body(application/form).
491507
extra_body: Extra information describing the request body(application/json).
492-
responses: response's model must be pydantic BaseModel.
508+
responses: API responses, should be BaseModel, dict or None.
493509
extra_responses: Extra information for responses.
494510
deprecated: Declares this operation to be deprecated.
495511
security: A declaration of which security mechanisms can be used for this operation.
@@ -505,6 +521,10 @@ def patch(
505521
warnings.warn(
506522
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
507523
DeprecationWarning)
524+
if extra_responses is not None:
525+
warnings.warn(
526+
"""`extra_responses` will be deprecated in v3.x, please use `responses` instead.""",
527+
DeprecationWarning)
508528

509529
def decorator(func) -> Callable:
510530
header, cookie, path, query, form, body = \

flask_openapi3/utils.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import inspect
66
import re
7-
from typing import get_type_hints, Dict, Type, Callable, List, Tuple, Optional, Any
7+
from typing import get_type_hints, Dict, Type, Callable, List, Tuple, Optional, Any, Union
88

99
from pydantic import BaseModel
1010

@@ -248,13 +248,13 @@ def parse_body(
248248

249249

250250
def get_responses(
251-
responses: dict,
251+
responses: Optional[Dict[str, Union[Type[BaseModel], Dict[Any, Any], None]]],
252252
extra_responses: Dict[str, dict],
253253
components_schemas: dict,
254254
operation: Operation
255255
) -> None:
256256
"""
257-
:param responses: Dict[str, BaseModel]
257+
:param responses: API responses, should be BaseModel, dict or None.
258258
:param extra_responses: Dict[str, dict]
259259
:param components_schemas: `models.component.py` `Components.schemas`
260260
:param operation: `models.path.py` Operation
@@ -281,8 +281,13 @@ def get_responses(
281281
)
282282
_schemas[UnprocessableEntity.__name__] = Schema(**UnprocessableEntity.schema())
283283
for key, response in responses.items():
284-
# Verify that the response is a class and that class is a subclass of `pydantic.BaseModel`
285-
if inspect.isclass(response) and issubclass(response, BaseModel):
284+
if response is None:
285+
# Verify that if the response is None, because http status code "204" means return "No Content"
286+
_responses[key] = Response(description=HTTP_STATUS.get(key, ""))
287+
continue
288+
if isinstance(response, dict):
289+
_responses[key] = response # type: ignore
290+
else:
286291
schema = response.schema(ref_template=OPENAPI3_REF_TEMPLATE)
287292
_responses[key] = Response(
288293
description=HTTP_STATUS.get(key, ""),
@@ -308,19 +313,15 @@ def get_responses(
308313
_content["application/json"].example = model_config.openapi_extra.get("example") # type: ignore
309314
_content["application/json"].examples = model_config.openapi_extra.get("examples") # type: ignore
310315
_content["application/json"].encoding = model_config.openapi_extra.get("encoding") # type: ignore
316+
if model_config.openapi_extra.get("content"):
317+
_responses[key].content.update(model_config.openapi_extra.get("content"))
311318

312319
_schemas[response.__name__] = Schema(**schema)
313320
definitions = schema.get("definitions")
314321
if definitions:
315322
for name, value in definitions.items():
316323
_schemas[name] = Schema(**value)
317-
# Verify that if the response is None, because http status code "204" means return "No Content"
318-
elif response is None:
319-
_responses[key] = Response(
320-
description=HTTP_STATUS.get(key, ""),
321-
)
322-
else:
323-
raise TypeError(f"{response} is invalid `pydantic.BaseModel`.")
324+
324325
# handle extra_responses
325326
for key, value in extra_responses.items():
326327
# key "200" value {"content":{"text/csv":{"schema":{"type": "string"}}}}

0 commit comments

Comments
 (0)