flask-openapi 4.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flask_openapi/__init__.py +44 -0
- flask_openapi/__version__.py +5 -0
- flask_openapi/blueprint.py +201 -0
- flask_openapi/commands.py +38 -0
- flask_openapi/models/__init__.py +91 -0
- flask_openapi/models/callback.py +18 -0
- flask_openapi/models/components.py +37 -0
- flask_openapi/models/contact.py +17 -0
- flask_openapi/models/data_type.py +18 -0
- flask_openapi/models/discriminator.py +16 -0
- flask_openapi/models/encoding.py +27 -0
- flask_openapi/models/example.py +19 -0
- flask_openapi/models/external_documentation.py +16 -0
- flask_openapi/models/file.py +27 -0
- flask_openapi/models/header.py +17 -0
- flask_openapi/models/info.py +24 -0
- flask_openapi/models/license.py +17 -0
- flask_openapi/models/link.py +23 -0
- flask_openapi/models/media_type.py +24 -0
- flask_openapi/models/oauth_flow.py +18 -0
- flask_openapi/models/oauth_flows.py +20 -0
- flask_openapi/models/operation.py +36 -0
- flask_openapi/models/parameter.py +34 -0
- flask_openapi/models/parameter_in_type.py +13 -0
- flask_openapi/models/path_item.py +36 -0
- flask_openapi/models/paths.py +9 -0
- flask_openapi/models/reference.py +14 -0
- flask_openapi/models/request_body.py +19 -0
- flask_openapi/models/response.py +23 -0
- flask_openapi/models/responses.py +11 -0
- flask_openapi/models/schema.py +59 -0
- flask_openapi/models/security_requirement.py +8 -0
- flask_openapi/models/security_scheme.py +25 -0
- flask_openapi/models/security_scheme_in_type.py +12 -0
- flask_openapi/models/server.py +19 -0
- flask_openapi/models/server_variable.py +17 -0
- flask_openapi/models/style_values.py +14 -0
- flask_openapi/models/tag.py +15 -0
- flask_openapi/models/validation_error.py +24 -0
- flask_openapi/models/xml.py +19 -0
- flask_openapi/openapi.py +449 -0
- flask_openapi/plugins.py +17 -0
- flask_openapi/py.typed +0 -0
- flask_openapi/request.py +250 -0
- flask_openapi/scaffold.py +547 -0
- flask_openapi/templates.py +113 -0
- flask_openapi/types.py +27 -0
- flask_openapi/utils.py +633 -0
- flask_openapi/view.py +230 -0
- flask_openapi-4.3.1.dist-info/METADATA +258 -0
- flask_openapi-4.3.1.dist-info/RECORD +53 -0
- flask_openapi-4.3.1.dist-info/WHEEL +4 -0
- flask_openapi-4.3.1.dist-info/licenses/LICENSE.rst +21 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# @Author : llc
|
|
3
|
+
# @Time : 2022/8/30 9:40
|
|
4
|
+
import inspect
|
|
5
|
+
from functools import wraps
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
|
|
8
|
+
from flask import current_app
|
|
9
|
+
from flask.wrappers import Response as FlaskResponse
|
|
10
|
+
|
|
11
|
+
from .models import ExternalDocumentation, Server, Tag
|
|
12
|
+
from .request import _validate_request
|
|
13
|
+
from .types import ParametersTuple, ResponseDict
|
|
14
|
+
from .utils import HTTPMethod
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class APIScaffold:
|
|
18
|
+
def _collect_openapi_info(
|
|
19
|
+
self,
|
|
20
|
+
rule: str,
|
|
21
|
+
func: Callable,
|
|
22
|
+
*,
|
|
23
|
+
tags: list[Tag] | None = None,
|
|
24
|
+
summary: str | None = None,
|
|
25
|
+
description: str | None = None,
|
|
26
|
+
external_docs: ExternalDocumentation | None = None,
|
|
27
|
+
operation_id: str | None = None,
|
|
28
|
+
responses: ResponseDict | None = None,
|
|
29
|
+
deprecated: bool | None = None,
|
|
30
|
+
security: list[dict[str, list[Any]]] | None = None,
|
|
31
|
+
servers: list[Server] | None = None,
|
|
32
|
+
openapi_extensions: dict[str, Any] | None = None,
|
|
33
|
+
doc_ui: bool = True,
|
|
34
|
+
method: str = HTTPMethod.GET,
|
|
35
|
+
) -> ParametersTuple:
|
|
36
|
+
raise NotImplementedError # pragma: no cover
|
|
37
|
+
|
|
38
|
+
def register_api(self, api) -> None:
|
|
39
|
+
raise NotImplementedError # pragma: no cover
|
|
40
|
+
|
|
41
|
+
def _add_url_rule(
|
|
42
|
+
self,
|
|
43
|
+
rule,
|
|
44
|
+
endpoint=None,
|
|
45
|
+
view_func=None,
|
|
46
|
+
provide_automatic_options=None,
|
|
47
|
+
**options,
|
|
48
|
+
) -> None:
|
|
49
|
+
raise NotImplementedError # pragma: no cover
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def create_view_func(
|
|
53
|
+
func,
|
|
54
|
+
header,
|
|
55
|
+
cookie,
|
|
56
|
+
path,
|
|
57
|
+
query,
|
|
58
|
+
form,
|
|
59
|
+
body,
|
|
60
|
+
raw,
|
|
61
|
+
view_class=None,
|
|
62
|
+
view_kwargs=None,
|
|
63
|
+
responses: ResponseDict | None = None,
|
|
64
|
+
validate_response: bool | None = None,
|
|
65
|
+
):
|
|
66
|
+
is_coroutine_function = inspect.iscoroutinefunction(func)
|
|
67
|
+
if is_coroutine_function:
|
|
68
|
+
|
|
69
|
+
@wraps(func)
|
|
70
|
+
async def view_func(**kwargs) -> FlaskResponse:
|
|
71
|
+
if hasattr(func, "__delay_validate_request__") and func.__delay_validate_request__ is True:
|
|
72
|
+
func_kwargs = kwargs
|
|
73
|
+
else:
|
|
74
|
+
func_kwargs = _validate_request(
|
|
75
|
+
header=header,
|
|
76
|
+
cookie=cookie,
|
|
77
|
+
path=path,
|
|
78
|
+
query=query,
|
|
79
|
+
form=form,
|
|
80
|
+
body=body,
|
|
81
|
+
raw=raw,
|
|
82
|
+
path_kwargs=kwargs,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# handle async request
|
|
86
|
+
if view_class:
|
|
87
|
+
signature = inspect.signature(view_class.__init__)
|
|
88
|
+
parameters = signature.parameters
|
|
89
|
+
if parameters.get("view_kwargs"):
|
|
90
|
+
view_object = view_class(view_kwargs=view_kwargs)
|
|
91
|
+
else:
|
|
92
|
+
view_object = view_class()
|
|
93
|
+
response = await func(view_object, **func_kwargs)
|
|
94
|
+
else:
|
|
95
|
+
response = await func(**func_kwargs)
|
|
96
|
+
|
|
97
|
+
if hasattr(current_app, "validate_response"):
|
|
98
|
+
if validate_response is None:
|
|
99
|
+
_validate_response = current_app.validate_response
|
|
100
|
+
else:
|
|
101
|
+
_validate_response = validate_response
|
|
102
|
+
else:
|
|
103
|
+
_validate_response = validate_response
|
|
104
|
+
|
|
105
|
+
if _validate_response and responses:
|
|
106
|
+
validate_response_callback = getattr(current_app, "validate_response_callback")
|
|
107
|
+
return validate_response_callback(response, responses)
|
|
108
|
+
|
|
109
|
+
return response
|
|
110
|
+
else:
|
|
111
|
+
|
|
112
|
+
@wraps(func)
|
|
113
|
+
def view_func(**kwargs) -> FlaskResponse:
|
|
114
|
+
if hasattr(func, "__delay_validate_request__") and func.__delay_validate_request__ is True:
|
|
115
|
+
func_kwargs = kwargs
|
|
116
|
+
else:
|
|
117
|
+
func_kwargs = _validate_request(
|
|
118
|
+
header=header,
|
|
119
|
+
cookie=cookie,
|
|
120
|
+
path=path,
|
|
121
|
+
query=query,
|
|
122
|
+
form=form,
|
|
123
|
+
body=body,
|
|
124
|
+
raw=raw,
|
|
125
|
+
path_kwargs=kwargs,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# handle request
|
|
129
|
+
if view_class:
|
|
130
|
+
signature = inspect.signature(view_class.__init__)
|
|
131
|
+
parameters = signature.parameters
|
|
132
|
+
if parameters.get("view_kwargs"):
|
|
133
|
+
view_object = view_class(view_kwargs=view_kwargs)
|
|
134
|
+
else:
|
|
135
|
+
view_object = view_class()
|
|
136
|
+
response = func(view_object, **func_kwargs)
|
|
137
|
+
else:
|
|
138
|
+
response = func(**func_kwargs)
|
|
139
|
+
|
|
140
|
+
if hasattr(current_app, "validate_response"):
|
|
141
|
+
if validate_response is None:
|
|
142
|
+
_validate_response = current_app.validate_response
|
|
143
|
+
else:
|
|
144
|
+
_validate_response = validate_response
|
|
145
|
+
else:
|
|
146
|
+
_validate_response = validate_response
|
|
147
|
+
|
|
148
|
+
if _validate_response and responses:
|
|
149
|
+
validate_response_callback = getattr(current_app, "validate_response_callback")
|
|
150
|
+
return validate_response_callback(response, responses)
|
|
151
|
+
|
|
152
|
+
return response
|
|
153
|
+
|
|
154
|
+
if not hasattr(func, "view"):
|
|
155
|
+
func.view = view_func
|
|
156
|
+
|
|
157
|
+
return func.view
|
|
158
|
+
|
|
159
|
+
def get(
|
|
160
|
+
self,
|
|
161
|
+
rule: str,
|
|
162
|
+
*,
|
|
163
|
+
tags: list[Tag] | None = None,
|
|
164
|
+
summary: str | None = None,
|
|
165
|
+
description: str | None = None,
|
|
166
|
+
external_docs: ExternalDocumentation | None = None,
|
|
167
|
+
operation_id: str | None = None,
|
|
168
|
+
responses: ResponseDict | None = None,
|
|
169
|
+
deprecated: bool | None = None,
|
|
170
|
+
security: list[dict[str, list[Any]]] | None = None,
|
|
171
|
+
servers: list[Server] | None = None,
|
|
172
|
+
openapi_extensions: dict[str, Any] | None = None,
|
|
173
|
+
validate_response: bool | None = None,
|
|
174
|
+
doc_ui: bool = True,
|
|
175
|
+
**options: Any,
|
|
176
|
+
) -> Callable:
|
|
177
|
+
"""
|
|
178
|
+
Decorator for defining a REST API endpoint with the HTTP GET method.
|
|
179
|
+
More information goto https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
rule: The URL rule string.
|
|
183
|
+
tags: Adds metadata to a single tag.
|
|
184
|
+
summary: A short summary of what the operation does.
|
|
185
|
+
description: A verbose explanation of the operation behavior.
|
|
186
|
+
external_docs: Additional external documentation for this operation.
|
|
187
|
+
operation_id: Unique string used to identify the operation.
|
|
188
|
+
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
|
|
189
|
+
deprecated: Declares this operation to be deprecated.
|
|
190
|
+
security: A declaration of which security mechanisms can be used for this operation.
|
|
191
|
+
servers: An alternative server array to service this operation.
|
|
192
|
+
openapi_extensions: Allows extensions to the OpenAPI Schema.
|
|
193
|
+
doc_ui: Declares this operation to be shown. Default to True.
|
|
194
|
+
validate_response: Verify the response body.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
def decorator(func) -> Callable:
|
|
198
|
+
header, cookie, path, query, form, body, raw = self._collect_openapi_info(
|
|
199
|
+
rule,
|
|
200
|
+
func,
|
|
201
|
+
tags=tags,
|
|
202
|
+
summary=summary,
|
|
203
|
+
description=description,
|
|
204
|
+
external_docs=external_docs,
|
|
205
|
+
operation_id=operation_id,
|
|
206
|
+
responses=responses,
|
|
207
|
+
deprecated=deprecated,
|
|
208
|
+
security=security,
|
|
209
|
+
servers=servers,
|
|
210
|
+
openapi_extensions=openapi_extensions,
|
|
211
|
+
doc_ui=doc_ui,
|
|
212
|
+
method=HTTPMethod.GET,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
_validate_response = validate_response if validate_response is not None else self.get_validate_response()
|
|
216
|
+
view_func = self.create_view_func(
|
|
217
|
+
func,
|
|
218
|
+
header,
|
|
219
|
+
cookie,
|
|
220
|
+
path,
|
|
221
|
+
query,
|
|
222
|
+
form,
|
|
223
|
+
body,
|
|
224
|
+
raw,
|
|
225
|
+
responses=responses,
|
|
226
|
+
validate_response=_validate_response,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
options.update({"methods": [HTTPMethod.GET]})
|
|
230
|
+
self._add_url_rule(rule, view_func=view_func, **options)
|
|
231
|
+
|
|
232
|
+
return func
|
|
233
|
+
|
|
234
|
+
return decorator
|
|
235
|
+
|
|
236
|
+
def post(
|
|
237
|
+
self,
|
|
238
|
+
rule: str,
|
|
239
|
+
*,
|
|
240
|
+
tags: list[Tag] | None = None,
|
|
241
|
+
summary: str | None = None,
|
|
242
|
+
description: str | None = None,
|
|
243
|
+
external_docs: ExternalDocumentation | None = None,
|
|
244
|
+
operation_id: str | None = None,
|
|
245
|
+
responses: ResponseDict | None = None,
|
|
246
|
+
deprecated: bool | None = None,
|
|
247
|
+
security: list[dict[str, list[Any]]] | None = None,
|
|
248
|
+
servers: list[Server] | None = None,
|
|
249
|
+
openapi_extensions: dict[str, Any] | None = None,
|
|
250
|
+
validate_response: bool | None = None,
|
|
251
|
+
doc_ui: bool = True,
|
|
252
|
+
**options: Any,
|
|
253
|
+
) -> Callable:
|
|
254
|
+
"""
|
|
255
|
+
Decorator for defining a REST API endpoint with the HTTP POST method.
|
|
256
|
+
More information goto https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
rule: The URL rule string.
|
|
260
|
+
tags: Adds metadata to a single tag.
|
|
261
|
+
summary: A short summary of what the operation does.
|
|
262
|
+
description: A verbose explanation of the operation behavior.
|
|
263
|
+
external_docs: Additional external documentation for this operation.
|
|
264
|
+
operation_id: Unique string used to identify the operation.
|
|
265
|
+
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
|
|
266
|
+
deprecated: Declares this operation to be deprecated.
|
|
267
|
+
security: A declaration of which security mechanisms can be used for this operation.
|
|
268
|
+
servers: An alternative server array to service this operation.
|
|
269
|
+
openapi_extensions: Allows extensions to the OpenAPI Schema.
|
|
270
|
+
doc_ui: Declares this operation to be shown. Default to True.
|
|
271
|
+
validate_response: Verify the response body.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
def decorator(func) -> Callable:
|
|
275
|
+
header, cookie, path, query, form, body, raw = self._collect_openapi_info(
|
|
276
|
+
rule,
|
|
277
|
+
func,
|
|
278
|
+
tags=tags,
|
|
279
|
+
summary=summary,
|
|
280
|
+
description=description,
|
|
281
|
+
external_docs=external_docs,
|
|
282
|
+
operation_id=operation_id,
|
|
283
|
+
responses=responses,
|
|
284
|
+
deprecated=deprecated,
|
|
285
|
+
security=security,
|
|
286
|
+
servers=servers,
|
|
287
|
+
openapi_extensions=openapi_extensions,
|
|
288
|
+
doc_ui=doc_ui,
|
|
289
|
+
method=HTTPMethod.POST,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
_validate_response = validate_response if validate_response is not None else self.get_validate_response()
|
|
293
|
+
view_func = self.create_view_func(
|
|
294
|
+
func,
|
|
295
|
+
header,
|
|
296
|
+
cookie,
|
|
297
|
+
path,
|
|
298
|
+
query,
|
|
299
|
+
form,
|
|
300
|
+
body,
|
|
301
|
+
raw,
|
|
302
|
+
responses=responses,
|
|
303
|
+
validate_response=_validate_response,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
options.update({"methods": [HTTPMethod.POST]})
|
|
307
|
+
self._add_url_rule(rule, view_func=view_func, **options)
|
|
308
|
+
|
|
309
|
+
return func
|
|
310
|
+
|
|
311
|
+
return decorator
|
|
312
|
+
|
|
313
|
+
def put(
|
|
314
|
+
self,
|
|
315
|
+
rule: str,
|
|
316
|
+
*,
|
|
317
|
+
tags: list[Tag] | None = None,
|
|
318
|
+
summary: str | None = None,
|
|
319
|
+
description: str | None = None,
|
|
320
|
+
external_docs: ExternalDocumentation | None = None,
|
|
321
|
+
operation_id: str | None = None,
|
|
322
|
+
responses: ResponseDict | None = None,
|
|
323
|
+
deprecated: bool | None = None,
|
|
324
|
+
security: list[dict[str, list[Any]]] | None = None,
|
|
325
|
+
servers: list[Server] | None = None,
|
|
326
|
+
openapi_extensions: dict[str, Any] | None = None,
|
|
327
|
+
validate_response: bool | None = None,
|
|
328
|
+
doc_ui: bool = True,
|
|
329
|
+
**options: Any,
|
|
330
|
+
) -> Callable:
|
|
331
|
+
"""
|
|
332
|
+
Decorator for defining a REST API endpoint with the HTTP PUT method.
|
|
333
|
+
More information goto https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
rule: The URL rule string.
|
|
337
|
+
tags: Adds metadata to a single tag.
|
|
338
|
+
summary: A short summary of what the operation does.
|
|
339
|
+
description: A verbose explanation of the operation behavior.
|
|
340
|
+
external_docs: Additional external documentation for this operation.
|
|
341
|
+
operation_id: Unique string used to identify the operation.
|
|
342
|
+
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
|
|
343
|
+
deprecated: Declares this operation to be deprecated.
|
|
344
|
+
security: A declaration of which security mechanisms can be used for this operation.
|
|
345
|
+
servers: An alternative server array to service this operation.
|
|
346
|
+
openapi_extensions: Allows extensions to the OpenAPI Schema.
|
|
347
|
+
doc_ui: Declares this operation to be shown. Default to True.
|
|
348
|
+
validate_response: Verify the response body.
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
def decorator(func) -> Callable:
|
|
352
|
+
header, cookie, path, query, form, body, raw = self._collect_openapi_info(
|
|
353
|
+
rule,
|
|
354
|
+
func,
|
|
355
|
+
tags=tags,
|
|
356
|
+
summary=summary,
|
|
357
|
+
description=description,
|
|
358
|
+
external_docs=external_docs,
|
|
359
|
+
operation_id=operation_id,
|
|
360
|
+
responses=responses,
|
|
361
|
+
deprecated=deprecated,
|
|
362
|
+
security=security,
|
|
363
|
+
servers=servers,
|
|
364
|
+
openapi_extensions=openapi_extensions,
|
|
365
|
+
doc_ui=doc_ui,
|
|
366
|
+
method=HTTPMethod.PUT,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
_validate_response = validate_response if validate_response is not None else self.get_validate_response()
|
|
370
|
+
view_func = self.create_view_func(
|
|
371
|
+
func,
|
|
372
|
+
header,
|
|
373
|
+
cookie,
|
|
374
|
+
path,
|
|
375
|
+
query,
|
|
376
|
+
form,
|
|
377
|
+
body,
|
|
378
|
+
raw,
|
|
379
|
+
responses=responses,
|
|
380
|
+
validate_response=_validate_response,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
options.update({"methods": [HTTPMethod.PUT]})
|
|
384
|
+
self._add_url_rule(rule, view_func=view_func, **options)
|
|
385
|
+
|
|
386
|
+
return func
|
|
387
|
+
|
|
388
|
+
return decorator
|
|
389
|
+
|
|
390
|
+
def delete(
|
|
391
|
+
self,
|
|
392
|
+
rule: str,
|
|
393
|
+
*,
|
|
394
|
+
tags: list[Tag] | None = None,
|
|
395
|
+
summary: str | None = None,
|
|
396
|
+
description: str | None = None,
|
|
397
|
+
external_docs: ExternalDocumentation | None = None,
|
|
398
|
+
operation_id: str | None = None,
|
|
399
|
+
responses: ResponseDict | None = None,
|
|
400
|
+
deprecated: bool | None = None,
|
|
401
|
+
security: list[dict[str, list[Any]]] | None = None,
|
|
402
|
+
servers: list[Server] | None = None,
|
|
403
|
+
openapi_extensions: dict[str, Any] | None = None,
|
|
404
|
+
validate_response: bool | None = None,
|
|
405
|
+
doc_ui: bool = True,
|
|
406
|
+
**options: Any,
|
|
407
|
+
) -> Callable:
|
|
408
|
+
"""
|
|
409
|
+
Decorator for defining a REST API endpoint with the HTTP DELETE method.
|
|
410
|
+
More information goto https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
rule: The URL rule string.
|
|
414
|
+
tags: Adds metadata to a single tag.
|
|
415
|
+
summary: A short summary of what the operation does.
|
|
416
|
+
description: A verbose explanation of the operation behavior.
|
|
417
|
+
external_docs: Additional external documentation for this operation.
|
|
418
|
+
operation_id: Unique string used to identify the operation.
|
|
419
|
+
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
|
|
420
|
+
deprecated: Declares this operation to be deprecated.
|
|
421
|
+
security: A declaration of which security mechanisms can be used for this operation.
|
|
422
|
+
servers: An alternative server array to service this operation.
|
|
423
|
+
openapi_extensions: Allows extensions to the OpenAPI Schema.
|
|
424
|
+
doc_ui: Declares this operation to be shown. Default to True.
|
|
425
|
+
validate_response: Verify the response body.
|
|
426
|
+
"""
|
|
427
|
+
|
|
428
|
+
def decorator(func) -> Callable:
|
|
429
|
+
header, cookie, path, query, form, body, raw = self._collect_openapi_info(
|
|
430
|
+
rule,
|
|
431
|
+
func,
|
|
432
|
+
tags=tags,
|
|
433
|
+
summary=summary,
|
|
434
|
+
description=description,
|
|
435
|
+
external_docs=external_docs,
|
|
436
|
+
operation_id=operation_id,
|
|
437
|
+
responses=responses,
|
|
438
|
+
deprecated=deprecated,
|
|
439
|
+
security=security,
|
|
440
|
+
servers=servers,
|
|
441
|
+
openapi_extensions=openapi_extensions,
|
|
442
|
+
doc_ui=doc_ui,
|
|
443
|
+
method=HTTPMethod.DELETE,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
_validate_response = validate_response if validate_response is not None else self.get_validate_response()
|
|
447
|
+
view_func = self.create_view_func(
|
|
448
|
+
func,
|
|
449
|
+
header,
|
|
450
|
+
cookie,
|
|
451
|
+
path,
|
|
452
|
+
query,
|
|
453
|
+
form,
|
|
454
|
+
body,
|
|
455
|
+
raw,
|
|
456
|
+
responses=responses,
|
|
457
|
+
validate_response=_validate_response,
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
options.update({"methods": [HTTPMethod.DELETE]})
|
|
461
|
+
self._add_url_rule(rule, view_func=view_func, **options)
|
|
462
|
+
|
|
463
|
+
return func
|
|
464
|
+
|
|
465
|
+
return decorator
|
|
466
|
+
|
|
467
|
+
def patch(
|
|
468
|
+
self,
|
|
469
|
+
rule: str,
|
|
470
|
+
*,
|
|
471
|
+
tags: list[Tag] | None = None,
|
|
472
|
+
summary: str | None = None,
|
|
473
|
+
description: str | None = None,
|
|
474
|
+
external_docs: ExternalDocumentation | None = None,
|
|
475
|
+
operation_id: str | None = None,
|
|
476
|
+
responses: ResponseDict | None = None,
|
|
477
|
+
deprecated: bool | None = None,
|
|
478
|
+
security: list[dict[str, list[Any]]] | None = None,
|
|
479
|
+
servers: list[Server] | None = None,
|
|
480
|
+
openapi_extensions: dict[str, Any] | None = None,
|
|
481
|
+
validate_response: bool | None = None,
|
|
482
|
+
doc_ui: bool = True,
|
|
483
|
+
**options: Any,
|
|
484
|
+
) -> Callable:
|
|
485
|
+
"""
|
|
486
|
+
Decorator for defining a REST API endpoint with the HTTP PATCH method.
|
|
487
|
+
More information goto https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
rule: The URL rule string.
|
|
491
|
+
tags: Adds metadata to a single tag.
|
|
492
|
+
summary: A short summary of what the operation does.
|
|
493
|
+
description: A verbose explanation of the operation behavior.
|
|
494
|
+
external_docs: Additional external documentation for this operation.
|
|
495
|
+
operation_id: Unique string used to identify the operation.
|
|
496
|
+
responses: API responses should be either a subclass of BaseModel, a dictionary, or None.
|
|
497
|
+
deprecated: Declares this operation to be deprecated.
|
|
498
|
+
security: A declaration of which security mechanisms can be used for this operation.
|
|
499
|
+
servers: An alternative server array to service this operation.
|
|
500
|
+
openapi_extensions: Allows extensions to the OpenAPI Schema.
|
|
501
|
+
doc_ui: Declares this operation to be shown. Default to True.
|
|
502
|
+
validate_response: Verify the response body.
|
|
503
|
+
"""
|
|
504
|
+
|
|
505
|
+
def decorator(func) -> Callable:
|
|
506
|
+
header, cookie, path, query, form, body, raw = self._collect_openapi_info(
|
|
507
|
+
rule,
|
|
508
|
+
func,
|
|
509
|
+
tags=tags,
|
|
510
|
+
summary=summary,
|
|
511
|
+
description=description,
|
|
512
|
+
external_docs=external_docs,
|
|
513
|
+
operation_id=operation_id,
|
|
514
|
+
responses=responses,
|
|
515
|
+
deprecated=deprecated,
|
|
516
|
+
security=security,
|
|
517
|
+
servers=servers,
|
|
518
|
+
openapi_extensions=openapi_extensions,
|
|
519
|
+
doc_ui=doc_ui,
|
|
520
|
+
method=HTTPMethod.PATCH,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
_validate_response = validate_response if validate_response is not None else self.get_validate_response()
|
|
524
|
+
view_func = self.create_view_func(
|
|
525
|
+
func,
|
|
526
|
+
header,
|
|
527
|
+
cookie,
|
|
528
|
+
path,
|
|
529
|
+
query,
|
|
530
|
+
form,
|
|
531
|
+
body,
|
|
532
|
+
raw,
|
|
533
|
+
responses=responses,
|
|
534
|
+
validate_response=_validate_response,
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
options.update({"methods": [HTTPMethod.PATCH]})
|
|
538
|
+
self._add_url_rule(rule, view_func=view_func, **options)
|
|
539
|
+
|
|
540
|
+
return func
|
|
541
|
+
|
|
542
|
+
return decorator
|
|
543
|
+
|
|
544
|
+
def get_validate_response(self):
|
|
545
|
+
if hasattr(self, "validate_response"):
|
|
546
|
+
if self.validate_response is not None:
|
|
547
|
+
return self.validate_response
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# @Author : llc
|
|
3
|
+
# @Time : 2023/2/16 9:46
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
openapi_html_string = """
|
|
7
|
+
<!DOCTYPE html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="UTF-8">
|
|
11
|
+
<title>APIdoc</title>
|
|
12
|
+
<link rel="shortcut icon" href="
|
|
13
|
+
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAkBJREFUSEutlU9oE1EQxr/ZPdiDRBR6K
|
|
14
|
+
KIepAhevFqwZqNByT+ziaQevEQRUQ8eBQ9iCyLkJFiKJ21FRLCY3SbZpSoxT4sWBQ/24MEe9OJdiURrd3dka9XUNtm31Xd8M/P9ZubNe48Qcg0W7F4sLPY5
|
|
15
|
+
GxbmZyeHvgaFU5BDu13Tq8Mg5fLy3kciuv5N/TLaDSQNiOVr55hp7O+EiGiOPb4mzNTEWslKAfy2qA7PAtjZsWLChCinTqxKQKZFWs46A+BGkC+BJhtGcqj
|
|
16
|
+
dT6qCWM6+z+BCEADAJ2GkNocCaMVGDz63AqfFF2Xg3VMjtSsU4IBuH/KIH0pkDxCuiHLqUiiApltFEMaDAMQ82jDT50MfclS3LhLhancA3RZGsriuMY1la4
|
|
17
|
+
dZoenOAK4LIx3vZA+cokTCjrR6+D0BW1aLcNNljs+YmVfrBviBWt4aB2ONFpAQRjLWrX2BFSwBVr5BbXr/CNh/tNqveGoJ4FynLF3X2TNTyc6FbpGWt4+Bu
|
|
18
|
+
QRgR9cJItwU5dSpUICobpWIcCFo9v/Y+e6i6559Xsk2u96DeOHxJsf5fg9AQl582ZPwUiXldP1BYkW7fh9yvFDZ7jhqjYGtRJgH00Zm3kaESAjYB8Xj40+m
|
|
19
|
+
0i9+xQROUaeXlEC3mN07vhApFGGmAYD2Al6/x97JZ+aRR0s2mey0nOX/Bf6f8HOxFxNmRsjESgEG89N9KrtvAPSCvRFhZoZlxKUr8B2jujVGwEDT9fa9rmZ
|
|
20
|
+
a/x3gCx7M2rvrU8m3suK+3w+AcssZ50vnfwAAAABJRU5ErkJggg==
|
|
21
|
+
">
|
|
22
|
+
<style>
|
|
23
|
+
body {
|
|
24
|
+
background-color: #131417;
|
|
25
|
+
display: flex;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
align-items: center;
|
|
28
|
+
height: 100vh;
|
|
29
|
+
margin: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.grid {
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-template-columns: repeat(6, 1fr);
|
|
35
|
+
grid-gap: 36px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.box {
|
|
39
|
+
grid-column: span 2;
|
|
40
|
+
width: 300px;
|
|
41
|
+
height: 200px;
|
|
42
|
+
background: #2c303a;
|
|
43
|
+
border-radius: 30px;
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
position: relative;
|
|
49
|
+
transform: scale(1);
|
|
50
|
+
transition: all .3s ease;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Dealing with 2 orphan items */
|
|
54
|
+
|
|
55
|
+
.box:last-child:nth-child(3n - 1) {
|
|
56
|
+
grid-column-end: -2;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.box:nth-last-child(2):nth-child(3n + 1) {
|
|
60
|
+
grid-column-end: 4;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Dealing with single orphan */
|
|
64
|
+
|
|
65
|
+
.box:last-child:nth-child(3n - 2) {
|
|
66
|
+
grid-column-end: 5;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.box:hover {
|
|
70
|
+
transform: scale(1.1);
|
|
71
|
+
box-shadow: 0 0 20px #333743f0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.box a {
|
|
75
|
+
color: white;
|
|
76
|
+
font-size: 30px;
|
|
77
|
+
user-select: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.box img {
|
|
81
|
+
user-select: none;
|
|
82
|
+
height: 64px;
|
|
83
|
+
margin-bottom: 10px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
</style>
|
|
87
|
+
|
|
88
|
+
</head>
|
|
89
|
+
<body>
|
|
90
|
+
<div class="grid">
|
|
91
|
+
{% for ui in ui_templates %}
|
|
92
|
+
<div class="box" onclick="window.location.href='{{ ui.name }}';return false">
|
|
93
|
+
<img height="64" src="{{ ui.name }}/images/{{ ui.name }}.svg">
|
|
94
|
+
<a>{{ ui.display_name }}</a>
|
|
95
|
+
</div>
|
|
96
|
+
{% else %}
|
|
97
|
+
<div style="color: white; grid-column: span 2; display: flex; flex-direction: column; grid-column-end: 5;">
|
|
98
|
+
<p>Please install at least one optional UI:</p>
|
|
99
|
+
<p style="font-family: Consolas; background-color: #404348; border-radius: 5px; padding: 5px; font-size: 12px">
|
|
100
|
+
$ pip install -U flask-openapi3[swagger,redoc,rapidoc,rapipdf,scalar,elements]
|
|
101
|
+
</p>
|
|
102
|
+
<p>More optional ui templates goto the document about
|
|
103
|
+
<a href="https://luolingchun.github.io/flask-openapi3/latest/Usage/UI_Templates/" style="color: #0969da">
|
|
104
|
+
UI_Templates.
|
|
105
|
+
</a>
|
|
106
|
+
</p>
|
|
107
|
+
</div>
|
|
108
|
+
{% endfor %}
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
</body>
|
|
112
|
+
</html>
|
|
113
|
+
"""
|
flask_openapi/types.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# @Author : llc
|
|
3
|
+
# @Time : 2023/7/9 15:25
|
|
4
|
+
from http import HTTPStatus
|
|
5
|
+
from typing import Any, Type
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from .models import RawModel, SecurityScheme
|
|
10
|
+
|
|
11
|
+
_ResponseDictValue = Type[BaseModel] | dict[Any, Any] | None
|
|
12
|
+
|
|
13
|
+
ResponseDict = dict[str | int | HTTPStatus, _ResponseDictValue]
|
|
14
|
+
|
|
15
|
+
ResponseStrKeyDict = dict[str, _ResponseDictValue]
|
|
16
|
+
|
|
17
|
+
SecuritySchemesDict = dict[str, SecurityScheme | dict[str, Any]]
|
|
18
|
+
|
|
19
|
+
ParametersTuple = tuple[
|
|
20
|
+
Type[BaseModel] | None,
|
|
21
|
+
Type[BaseModel] | None,
|
|
22
|
+
Type[BaseModel] | None,
|
|
23
|
+
Type[BaseModel] | None,
|
|
24
|
+
Type[BaseModel] | None,
|
|
25
|
+
Type[BaseModel] | None,
|
|
26
|
+
Type[RawModel] | None,
|
|
27
|
+
]
|