Skip to content

Commit f4e4b1b

Browse files
committed
BaseModel Config support openapi_extra
1 parent 035c127 commit f4e4b1b

File tree

8 files changed

+216
-97
lines changed

8 files changed

+216
-97
lines changed

examples/openapi_extra.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : llc
3+
# @Time : 2023/6/1 15:04
4+
from typing import List
5+
6+
from pydantic import BaseModel
7+
8+
from flask_openapi3 import OpenAPI, FileStorage
9+
10+
app = OpenAPI(__name__)
11+
12+
13+
class UploadFilesForm(BaseModel):
14+
file: FileStorage
15+
str_list: List[str]
16+
17+
class Config:
18+
openapi_extra = {
19+
# "example": {"a": 123},
20+
"examples": {
21+
"Example 01": {
22+
"summary": "An example",
23+
"value": {
24+
"file": "Example-01.jpg",
25+
"str_list": ["a", "b", "c"]
26+
}
27+
},
28+
"Example 02": {
29+
"summary": "Another example",
30+
"value": {
31+
"str_list": ["1", "2", "3"]
32+
}
33+
}
34+
}
35+
}
36+
37+
38+
class BookBody(BaseModel):
39+
age: int
40+
author: str
41+
42+
class Config:
43+
openapi_extra = {
44+
"description": "This is post RequestBody",
45+
"example": {"age": 12, "author": "author1"},
46+
"examples": {
47+
"example1": {
48+
"summary": "example summary1",
49+
"description": "example description1",
50+
"value": {
51+
"age": 24,
52+
"author": "author2"
53+
}
54+
},
55+
"example2": {
56+
"summary": "example summary2",
57+
"description": "example description2",
58+
"value": {
59+
"age": 48,
60+
"author": "author3"
61+
}
62+
}
63+
64+
}}
65+
66+
67+
@app.post('/upload/files')
68+
def upload_files(form: UploadFilesForm):
69+
print(form.file)
70+
print(form.str_list)
71+
return {"code": 0, "message": "ok"}
72+
73+
74+
@app.post('/book', )
75+
def create_book(body: BookBody):
76+
print(body)
77+
return {"code": 0, "message": "ok"}
78+
79+
80+
if __name__ == "__main__":
81+
app.run(debug=True)

examples/response_demo.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# @Author : [martinatseequent](https://github.com/martinatseequent)
2+
# @Author : llc
33
# @Time : 2021/6/22 9:32
44

55
import json
@@ -23,6 +23,25 @@ class HelloPath(BaseModel):
2323
class Message(BaseModel):
2424
message: str = Field(..., description="The message")
2525

26+
class Config:
27+
openapi_extra = {
28+
# "example": {"message": "aaa"},
29+
"examples": {
30+
"example1": {
31+
"summary": "example1 summary",
32+
"value": {
33+
"message": "bbb"
34+
}
35+
},
36+
"example2": {
37+
"summary": "example2 summary",
38+
"value": {
39+
"message": "ccc"
40+
}
41+
}
42+
}
43+
}
44+
2645

2746
@bp.get("/hello/<string:name>", responses={"200": Message})
2847
def hello(path: HelloPath):

examples/rest_demo.py

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from pydantic import BaseModel, Field
88

9-
from flask_openapi3 import ExternalDocumentation, ExtraRequestBody, Example
9+
from flask_openapi3 import ExternalDocumentation
1010
from flask_openapi3 import Info, Tag, Server
1111
from flask_openapi3 import OpenAPI
1212

@@ -128,32 +128,7 @@ def get_books(query: BookQuery):
128128
}
129129

130130

131-
extra_body = ExtraRequestBody(
132-
description="This is post RequestBody",
133-
required=True,
134-
example="ttt",
135-
examples={
136-
"example1": Example(
137-
summary="example summary1",
138-
description="example description1",
139-
value={
140-
"age": 24,
141-
"author": "author1"
142-
}
143-
),
144-
"example2": Example(
145-
summary="example summary2",
146-
description="example description2",
147-
value={
148-
"age": 48,
149-
"author": "author2"
150-
}
151-
)
152-
}
153-
)
154-
155-
156-
@app.post('/book', tags=[book_tag], responses={"200": BookResponse}, extra_body=extra_body)
131+
@app.post('/book', tags=[book_tag], responses={"200": BookResponse})
157132
def create_book(body: BookBody):
158133
print(body)
159134
return {"code": 0, "message": "ok"}, HTTPStatus.OK

examples/upload_file_demo.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
from pydantic import BaseModel, Field
88

9-
from flask_openapi3 import OpenAPI, FileStorage, ExtraRequestBody
10-
from flask_openapi3 import Encoding
9+
from flask_openapi3 import OpenAPI, FileStorage
1110

1211
app = OpenAPI(__name__)
1312

@@ -23,14 +22,6 @@ class UploadFilesForm(BaseModel):
2322
int_list: List[int]
2423

2524

26-
extra_form = ExtraRequestBody(
27-
description="This is form RequestBody",
28-
required=True,
29-
# replace style (default to form)
30-
encoding={"str_list": Encoding(style="simple")}
31-
)
32-
33-
3425
@app.post('/upload/file')
3526
def upload_file(form: UploadFileForm):
3627
print(form.file.filename)
@@ -39,7 +30,7 @@ def upload_file(form: UploadFileForm):
3930
return {"code": 0, "message": "ok"}
4031

4132

42-
@app.post('/upload/files', extra_form=extra_form)
33+
@app.post('/upload/files')
4334
def upload_files(form: UploadFilesForm):
4435
print(form.files)
4536
print(form.str_list)

flask_openapi3/scaffold.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import functools
55
import inspect
66
import sys
7+
import warnings
78
from abc import ABC
89
from functools import wraps
910
from typing import Callable, List, Optional, Dict, Type, Any, Tuple
@@ -31,6 +32,8 @@ def iscoroutinefunction(func: Any) -> bool:
3132

3233
return inspect.iscoroutinefunction(func)
3334

35+
warnings.simplefilter("once")
36+
3437

3538
class APIScaffold(Scaffold, ABC):
3639
def _do_decorator(
@@ -174,6 +177,15 @@ def get(
174177
doc_ui: Add openapi document UI(swagger, rapidoc and redoc). Defaults to True.
175178
"""
176179

180+
if extra_form is not None:
181+
warnings.warn(
182+
"""`extra_form` will be deprecated in v3.x, please use `openapi_extra` instead.""",
183+
DeprecationWarning)
184+
if extra_body is not None:
185+
warnings.warn(
186+
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
187+
DeprecationWarning)
188+
177189
def decorator(func) -> Callable:
178190
header, cookie, path, query, form, body = \
179191
self._do_decorator(
@@ -245,6 +257,14 @@ def post(
245257
openapi_extensions: Allows extensions to the OpenAPI Schema.
246258
doc_ui: Declares this operation to be shown.
247259
"""
260+
if extra_form is not None:
261+
warnings.warn(
262+
"""`extra_form` will be deprecated in v3.x, please use `openapi_extra` instead.""",
263+
DeprecationWarning)
264+
if extra_body is not None:
265+
warnings.warn(
266+
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
267+
DeprecationWarning)
248268

249269
def decorator(func) -> Callable:
250270
header, cookie, path, query, form, body = \
@@ -317,6 +337,14 @@ def put(
317337
openapi_extensions: Allows extensions to the OpenAPI Schema.
318338
doc_ui: Declares this operation to be shown.
319339
"""
340+
if extra_form is not None:
341+
warnings.warn(
342+
"""`extra_form` will be deprecated in v3.x, please use `openapi_extra` instead.""",
343+
DeprecationWarning)
344+
if extra_body is not None:
345+
warnings.warn(
346+
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
347+
DeprecationWarning)
320348

321349
def decorator(func) -> Callable:
322350
header, cookie, path, query, form, body = \
@@ -389,6 +417,14 @@ def delete(
389417
openapi_extensions: Allows extensions to the OpenAPI Schema.
390418
doc_ui: Declares this operation to be shown.
391419
"""
420+
if extra_form is not None:
421+
warnings.warn(
422+
"""`extra_form` will be deprecated in v3.x, please use `openapi_extra` instead.""",
423+
DeprecationWarning)
424+
if extra_body is not None:
425+
warnings.warn(
426+
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
427+
DeprecationWarning)
392428

393429
def decorator(func) -> Callable:
394430
header, cookie, path, query, form, body = \
@@ -461,6 +497,14 @@ def patch(
461497
openapi_extensions: Allows extensions to the OpenAPI Schema.
462498
doc_ui: Declares this operation to be shown.
463499
"""
500+
if extra_form is not None:
501+
warnings.warn(
502+
"""`extra_form` will be deprecated in v3.x, please use `openapi_extra` instead.""",
503+
DeprecationWarning)
504+
if extra_body is not None:
505+
warnings.warn(
506+
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
507+
DeprecationWarning)
464508

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

flask_openapi3/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,17 @@ def get_responses(
298298
)
299299
}
300300
)
301+
302+
model_config = response.Config
303+
if hasattr(model_config, "openapi_extra"):
304+
_responses[key].description = model_config.openapi_extra.get("description")
305+
_responses[key].headers = model_config.openapi_extra.get("headers")
306+
_responses[key].links = model_config.openapi_extra.get("links")
307+
_content = _responses[key].content
308+
_content["application/json"].example = model_config.openapi_extra.get("example") # type: ignore
309+
_content["application/json"].examples = model_config.openapi_extra.get("examples") # type: ignore
310+
_content["application/json"].encoding = model_config.openapi_extra.get("encoding") # type: ignore
311+
301312
_schemas[response.__name__] = Schema(**schema)
302313
definitions = schema.get("definitions")
303314
if definitions:
@@ -407,6 +418,13 @@ def parse_parameters(
407418
request_body = RequestBody(**{
408419
"content": _content,
409420
})
421+
model_config = form.Config
422+
if hasattr(model_config, "openapi_extra"):
423+
request_body.description = model_config.openapi_extra.get("description")
424+
request_body.content["multipart/form-data"].example = model_config.openapi_extra.get("example")
425+
request_body.content["multipart/form-data"].examples = model_config.openapi_extra.get("examples")
426+
if model_config.openapi_extra.get("encoding"):
427+
request_body.content["multipart/form-data"].encoding = model_config.openapi_extra.get("encoding")
410428
operation.requestBody = request_body
411429
if body:
412430
_content, _components_schemas = parse_body(body, extra_body)
@@ -419,6 +437,12 @@ def parse_parameters(
419437
)
420438
else:
421439
request_body = RequestBody(content=_content)
440+
model_config = body.Config
441+
if hasattr(model_config, "openapi_extra"):
442+
request_body.description = model_config.openapi_extra.get("description")
443+
request_body.content["application/json"].example = model_config.openapi_extra.get("example")
444+
request_body.content["application/json"].examples = model_config.openapi_extra.get("examples")
445+
request_body.content["application/json"].encoding = model_config.openapi_extra.get("encoding")
422446
operation.requestBody = request_body
423447
operation.parameters = parameters if parameters else None
424448

flask_openapi3/view.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# @Time : 2022/10/14 16:09
44
import re
55
import typing
6+
import warnings
67

78
if typing.TYPE_CHECKING:
89
from .openapi import OpenAPI
@@ -19,6 +20,8 @@
1920
from .utils import get_operation, parse_and_store_tags, parse_parameters, get_responses, parse_method, \
2021
get_operation_id_for_path
2122

23+
warnings.simplefilter("once")
24+
2225

2326
class APIView:
2427
def __init__(
@@ -135,6 +138,15 @@ def doc(
135138
doc_ui: Add openapi document UI(swagger, rapidoc and redoc). Defaults to True.
136139
"""
137140

141+
if extra_form is not None:
142+
warnings.warn(
143+
"""`extra_form` will be deprecated in v3.x, please use `openapi_extra` instead.""",
144+
DeprecationWarning)
145+
if extra_body is not None:
146+
warnings.warn(
147+
"""`extra_body` will be deprecated in v3.x, please use `openapi_extra` instead.""",
148+
DeprecationWarning)
149+
138150
if responses is None:
139151
responses = {}
140152
if extra_responses is None:

0 commit comments

Comments
 (0)