mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-26 07:40:57 -05:00
Compare commits
20 Commits
refactor-i
...
0.75.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b54432a9c | ||
|
|
acd2287b57 | ||
|
|
1d106bd959 | ||
|
|
77fc14eb69 | ||
|
|
41d75b6d1c | ||
|
|
ddd9da3db4 | ||
|
|
197c1d6dd7 | ||
|
|
d9e7a541fd | ||
|
|
c449ae5c74 | ||
|
|
1d8d81a6d5 | ||
|
|
d81c908132 | ||
|
|
cb4da93643 | ||
|
|
3cbfae16cf | ||
|
|
0def8382b8 | ||
|
|
02fae6a38e | ||
|
|
75af472029 | ||
|
|
e1135eddb5 | ||
|
|
acf8a91c25 | ||
|
|
c4f361c0c4 | ||
|
|
cc57bfcf60 |
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v02
|
||||
- name: Install Flit
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install flit
|
||||
@@ -38,4 +38,4 @@ jobs:
|
||||
- name: Test
|
||||
run: bash scripts/test.sh
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v2
|
||||
|
||||
@@ -49,15 +49,13 @@ The key features are:
|
||||
|
||||
<a href="https://bit.ly/2QSouzH" target="_blank" title="Jina: build neural search-as-a-service for any kind of data in just minutes."><img src="https://fastapi.tiangolo.com/img/sponsors/jina.svg"></a>
|
||||
<a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a>
|
||||
<a href="https://www.dropbase.io/careers" target="_blank" title="Dropbase - seamlessly collect, clean, and centralize data."><img src="https://fastapi.tiangolo.com/img/sponsors/dropbase.svg"></a>
|
||||
<a href="https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings" target="_blank" title="https://striveworks.us/careers"><img src="https://fastapi.tiangolo.com/img/sponsors/striveworks.png"></a>
|
||||
<a href="https://classiq.link/n4s" target="_blank" title="Join the team building a new SaaS platform that will change the computing world"><img src="https://fastapi.tiangolo.com/img/sponsors/classiq.png"></a>
|
||||
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
|
||||
<a href="https://www.investsuite.com/jobs" target="_blank" title="Wealthtech jobs with FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/investsuite.svg"></a>
|
||||
<a href="https://www.vim.so/?utm_source=FastAPI" target="_blank" title="We help you master vim with interactive exercises"><img src="https://fastapi.tiangolo.com/img/sponsors/vimso.png"></a>
|
||||
<a href="https://talkpython.fm/fastapi-sponsor" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
|
||||
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
|
||||
<a href="https://github.com/deepset-ai/haystack/" target="_blank" title="Build powerful search from composable, open source building blocks"><img src="https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg"></a>
|
||||
<a href="https://www.udemy.com/course/fastapi-rest/" target="_blank" title="Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails."><img src="https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg"></a>
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
|
||||
@@ -5,12 +5,6 @@ gold:
|
||||
- url: https://cryptapi.io/
|
||||
title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway."
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg
|
||||
- url: https://www.dropbase.io/careers
|
||||
title: Dropbase - seamlessly collect, clean, and centralize data.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg
|
||||
- url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings
|
||||
title: https://striveworks.us/careers
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png
|
||||
- url: https://classiq.link/n4s
|
||||
title: Join the team building a new SaaS platform that will change the computing world
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/classiq.png
|
||||
@@ -21,9 +15,6 @@ silver:
|
||||
- url: https://www.investsuite.com/jobs
|
||||
title: Wealthtech jobs with FastAPI
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg
|
||||
- url: https://www.vim.so/?utm_source=FastAPI
|
||||
title: We help you master vim with interactive exercises
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/vimso.png
|
||||
- url: https://talkpython.fm/fastapi-sponsor
|
||||
title: FastAPI video courses on demand from people you trust
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/talkpython.png
|
||||
@@ -33,7 +24,13 @@ silver:
|
||||
- url: https://github.com/deepset-ai/haystack/
|
||||
title: Build powerful search from composable, open source building blocks
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg
|
||||
- url: https://www.udemy.com/course/fastapi-rest/
|
||||
title: Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg
|
||||
bronze:
|
||||
- url: https://calmcode.io
|
||||
title: Code. Simply. Clearly. Calmly.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/calmcode.jpg
|
||||
- url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
|
||||
title: Biosecurity risk assessments made easy.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png
|
||||
- url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings
|
||||
title: https://striveworks.us/careers
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png
|
||||
|
||||
@@ -2,10 +2,9 @@ logins:
|
||||
- jina-ai
|
||||
- deta
|
||||
- investsuite
|
||||
- vimsoHQ
|
||||
- mikeckennedy
|
||||
- koaning
|
||||
- deepset-ai
|
||||
- cryptapi
|
||||
- DropbaseHQ
|
||||
- Striveworks
|
||||
- xoflare
|
||||
- InesIvanova
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/exoflare.png
Normal file
BIN
docs/en/docs/img/sponsors/exoflare.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
docs/en/docs/img/sponsors/fastapi-course-bundle-banner.png
Normal file
BIN
docs/en/docs/img/sponsors/fastapi-course-bundle-banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/en/docs/img/sponsors/ines-course.jpg
Normal file
BIN
docs/en/docs/img/sponsors/ines-course.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -3,6 +3,27 @@
|
||||
## Latest Changes
|
||||
|
||||
|
||||
## 0.75.2
|
||||
|
||||
This release includes upgrades to third-party packages that handle security issues. Although there's a chance these issues don't affect you in particular, please upgrade as soon as possible.
|
||||
|
||||
### Fixes
|
||||
|
||||
* ✅ Fix new/recent tests with new fixed `ValidationError` JSON Schema. PR [#4806](https://github.com/tiangolo/fastapi/pull/4806) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix JSON Schema for `ValidationError` at field `loc`. PR [#3810](https://github.com/tiangolo/fastapi/pull/3810) by [@dconathan](https://github.com/dconathan).
|
||||
* 🐛 Fix support for prefix on APIRouter WebSockets. PR [#2640](https://github.com/tiangolo/fastapi/pull/2640) by [@Kludex](https://github.com/Kludex).
|
||||
|
||||
### Upgrades
|
||||
|
||||
* ⬆️ Update ujson ranges for CVE-2021-45958. PR [#4804](https://github.com/tiangolo/fastapi/pull/4804) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Upgrade dependencies upper range for extras "all". PR [#4803](https://github.com/tiangolo/fastapi/pull/4803) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Upgrade Swagger UI - swagger-ui-dist@4. This handles a security issue in Swagger UI itself where it could be possible to inject HTML into Swagger UI. Please upgrade as soon as you can, in particular if you expose your Swagger UI (`/docs`) publicly to non-expert users. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔧 Update sponsors, add: ExoFlare, Ines Course; remove: Dropbase, Vim.so, Calmcode; update: Striveworks, TalkPython and TestDriven.io. PR [#4805](https://github.com/tiangolo/fastapi/pull/4805) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.75.1
|
||||
|
||||
### Translations
|
||||
|
||||
@@ -22,16 +22,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="announce-right" style="position: relative;">
|
||||
<!-- <div class="item">
|
||||
<a title="The launchpad for all your (team's) ideas" style="display: block; position: relative;" href="https://www.deta.sh/?ref=fastapi" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/deta-banner.svg" />
|
||||
</a>
|
||||
</div> -->
|
||||
<div class="item">
|
||||
<a title="Get three courses at 10% off their current prices! Plus, we'll be donating 10% of all profits from sales of this bundle to the FastAPI team." style="display: block; position: relative;" href="https://testdriven.io/talkpython/" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/fastapi-course-bundle-banner.svg" />
|
||||
<img class="sponsor-image" src="/img/sponsors/fastapi-course-bundle-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
@@ -46,18 +40,6 @@
|
||||
<img class="sponsor-image" src="/img/sponsors/cryptapi-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Dropbase - seamlessly collect, clean, and centralize data." style="display: block; position: relative;" href="https://www.dropbase.io/careers" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/dropbase-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="https://striveworks.us/careers" style="display: block; position: relative;" href="https://striveworks.us/careers?utm_source=fastapi&utm_medium=small_banner&utm_campaign=feb_march#openings" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/striveworks-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Join the team building a new SaaS platform that will change the computing world" style="display: block; position: relative;" href="https://classiq.link/mzg" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.75.1"
|
||||
__version__ = "0.75.2"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -137,10 +137,6 @@ class FastAPI(Starlette):
|
||||
self.middleware_stack: ASGIApp = self.build_middleware_stack()
|
||||
self.setup()
|
||||
|
||||
@property
|
||||
def routes(self) -> List[BaseRoute]:
|
||||
return list(self.router.iter_all_routes())
|
||||
|
||||
def build_middleware_stack(self) -> ASGIApp:
|
||||
# Duplicate/override from Starlette to add AsyncExitStackMiddleware
|
||||
# inside of ExceptionMiddleware, inside of custom user middlewares
|
||||
|
||||
@@ -17,8 +17,8 @@ def get_swagger_ui_html(
|
||||
*,
|
||||
openapi_url: str,
|
||||
title: str,
|
||||
swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js",
|
||||
swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css",
|
||||
swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js",
|
||||
swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css",
|
||||
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
|
||||
oauth2_redirect_url: Optional[str] = None,
|
||||
init_oauth: Optional[Dict[str, Any]] = None,
|
||||
|
||||
@@ -38,7 +38,11 @@ validation_error_definition = {
|
||||
"title": "ValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {"title": "Location", "type": "array", "items": {"type": "string"}},
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
@@ -152,7 +156,7 @@ def generate_operation_id(
|
||||
)
|
||||
if route.operation_id:
|
||||
return route.operation_id
|
||||
path: str = route._route_full_path_format
|
||||
path: str = route.path_format
|
||||
return generate_operation_id_for_path(name=route.name, path=path, method=method)
|
||||
|
||||
|
||||
@@ -243,7 +247,7 @@ def get_openapi_path(
|
||||
model_name_map=model_name_map,
|
||||
operation_ids=operation_ids,
|
||||
)
|
||||
callbacks[callback.name] = {callback._route_full_path: cb_path}
|
||||
callbacks[callback.name] = {callback.path: cb_path}
|
||||
operation["callbacks"] = callbacks
|
||||
if route.status_code is not None:
|
||||
status_code = str(route.status_code)
|
||||
@@ -422,7 +426,7 @@ def get_openapi(
|
||||
if result:
|
||||
path, security_schemes, path_definitions = result
|
||||
if path:
|
||||
paths.setdefault(route._route_full_path_format, {}).update(path)
|
||||
paths.setdefault(route.path_format, {}).update(path)
|
||||
if security_schemes:
|
||||
components.setdefault("securitySchemes", {}).update(
|
||||
security_schemes
|
||||
|
||||
@@ -9,14 +9,12 @@ from typing import (
|
||||
Callable,
|
||||
Coroutine,
|
||||
Dict,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
Set,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
|
||||
@@ -59,10 +57,6 @@ from starlette.status import WS_1008_POLICY_VIOLATION
|
||||
from starlette.types import ASGIApp, Scope
|
||||
from starlette.websockets import WebSocket
|
||||
|
||||
APIRouteType = TypeVar("APIRouteType", bound="APIRoute")
|
||||
APIRouterType = TypeVar("APIRouterType", bound="APIRouter")
|
||||
APIMountType = TypeVar("APIMountType", bound="APIMount")
|
||||
|
||||
|
||||
def _prepare_response_content(
|
||||
res: Any,
|
||||
@@ -311,8 +305,6 @@ class APIWebSocketRoute(routing.WebSocketRoute):
|
||||
|
||||
|
||||
class APIRoute(routing.Route):
|
||||
_route_full_path_format: str # only for mypy
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
path: str,
|
||||
@@ -346,13 +338,13 @@ class APIRoute(routing.Route):
|
||||
generate_unique_id_function: Union[
|
||||
Callable[["APIRoute"], str], DefaultPlaceholder
|
||||
] = Default(generate_unique_id),
|
||||
router: Optional["APIRouter"] = None,
|
||||
) -> None:
|
||||
self.path = path
|
||||
self.endpoint = endpoint
|
||||
self.response_model = response_model
|
||||
self.summary = summary
|
||||
self.response_description = response_description
|
||||
self.deprecated = deprecated
|
||||
self.operation_id = operation_id
|
||||
self.response_model_include = response_model_include
|
||||
self.response_model_exclude = response_model_exclude
|
||||
@@ -360,128 +352,34 @@ class APIRoute(routing.Route):
|
||||
self.response_model_exclude_unset = response_model_exclude_unset
|
||||
self.response_model_exclude_defaults = response_model_exclude_defaults
|
||||
self.response_model_exclude_none = response_model_exclude_none
|
||||
self.include_in_schema = include_in_schema
|
||||
self.response_class = response_class
|
||||
self.dependency_overrides_provider = dependency_overrides_provider
|
||||
self.callbacks = callbacks
|
||||
self.openapi_extra = openapi_extra
|
||||
self.router = router
|
||||
|
||||
self.generate_unique_id_function = generate_unique_id_function
|
||||
self.tags = tags or []
|
||||
self.responses = responses or {}
|
||||
self.name = get_name(endpoint) if name is None else name
|
||||
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
|
||||
if methods is None:
|
||||
methods = ["GET"]
|
||||
self.methods: Set[str] = set([method.upper() for method in methods])
|
||||
if isinstance(generate_unique_id_function, DefaultPlaceholder):
|
||||
current_generate_unique_id: Callable[
|
||||
["APIRoute"], str
|
||||
] = generate_unique_id_function.value
|
||||
else:
|
||||
current_generate_unique_id = generate_unique_id_function
|
||||
self.unique_id = self.operation_id or current_generate_unique_id(self)
|
||||
# normalize enums e.g. http.HTTPStatus
|
||||
if isinstance(status_code, IntEnum):
|
||||
status_code = int(status_code)
|
||||
self.status_code = status_code
|
||||
if methods is None:
|
||||
methods = ["GET"]
|
||||
self.methods: Set[str] = set([method.upper() for method in methods])
|
||||
|
||||
self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
|
||||
# if a "form feed" character (page break) is found in the description text,
|
||||
# truncate description text to the content preceding the first "form feed"
|
||||
self.description = self.description.split("\f")[0]
|
||||
|
||||
assert callable(endpoint), "An endpoint must be a callable"
|
||||
|
||||
self.path_regex, self.path_format, self.param_convertors = compile_path(
|
||||
self.path
|
||||
)
|
||||
|
||||
# Attributes set in route used to compute resolved attributes
|
||||
self._route_deprecated = deprecated
|
||||
self._route_include_in_schema = include_in_schema
|
||||
self._route_response_class = response_class
|
||||
self._route_callbacks = callbacks
|
||||
self._route_generate_unique_id_function = generate_unique_id_function
|
||||
self._route_tags = tags or []
|
||||
self._route_responses = responses or {}
|
||||
if dependencies:
|
||||
self._route_dependencies = dependencies
|
||||
else:
|
||||
self._route_dependencies = []
|
||||
|
||||
self.setup()
|
||||
|
||||
def setup(self) -> None:
|
||||
# setup full path
|
||||
self._route_full_path = self.path
|
||||
if self.router:
|
||||
self._route_full_path = self.router._router_full_path + self.path
|
||||
|
||||
# setup dependencies
|
||||
self.dependencies: List[params.Depends] = []
|
||||
if self.router:
|
||||
self.dependencies.extend(self.router.dependencies)
|
||||
self.dependencies.extend(self._route_dependencies)
|
||||
|
||||
# setup generate_unique_id
|
||||
generate_unique_id_functions: List[
|
||||
Union[Callable[[APIRoute], str], DefaultPlaceholder]
|
||||
] = [self._route_generate_unique_id_function]
|
||||
if self.router:
|
||||
generate_unique_id_functions.append(self.router.generate_unique_id_function)
|
||||
current_generate_unique_id_function = get_value_or_default(
|
||||
*generate_unique_id_functions
|
||||
)
|
||||
self.generate_unique_id_function: Union[
|
||||
Callable[[APIRoute], str], DefaultPlaceholder
|
||||
] = current_generate_unique_id_function
|
||||
|
||||
# setup responses
|
||||
responses: Dict[Union[int, str], Dict[str, Any]] = {}
|
||||
if self.router:
|
||||
responses.update(self.router.responses)
|
||||
responses.update(self._route_responses)
|
||||
self.responses: Dict[Union[int, str], Dict[str, Any]] = responses
|
||||
|
||||
# setup default_response_class
|
||||
default_response_classes: List[Union[Type[Response], DefaultPlaceholder]] = [
|
||||
self._route_response_class
|
||||
]
|
||||
if self.router:
|
||||
default_response_classes.append(self.router.default_response_class)
|
||||
current_default_response_class = get_value_or_default(*default_response_classes)
|
||||
self.response_class: Union[
|
||||
Type[Response], DefaultPlaceholder
|
||||
] = current_default_response_class
|
||||
|
||||
# setup tags
|
||||
self.tags: List[Union[str, Enum]] = []
|
||||
if self.router:
|
||||
self.tags.extend(self.router.tags)
|
||||
self.tags.extend(self._route_tags)
|
||||
|
||||
# setup callbacks
|
||||
callbacks: List[BaseRoute] = []
|
||||
if self.router:
|
||||
callbacks.extend(self.router.callbacks)
|
||||
if self._route_callbacks:
|
||||
callbacks.extend(self._route_callbacks)
|
||||
self.callbacks = callbacks
|
||||
|
||||
# setup deprecated
|
||||
self.deprecated = self._route_deprecated
|
||||
if self.router:
|
||||
self.deprecated = self._route_deprecated or self.router.deprecated
|
||||
|
||||
# setup include_in_schema
|
||||
self.include_in_schema = self._route_include_in_schema
|
||||
if self.router:
|
||||
self.include_in_schema = (
|
||||
self._route_include_in_schema and self.router.include_in_schema
|
||||
)
|
||||
|
||||
_, self._route_full_path_format, _ = compile_path(self._route_full_path)
|
||||
|
||||
if isinstance(self.generate_unique_id_function, DefaultPlaceholder):
|
||||
resolved_generate_unique_id: Callable[
|
||||
["APIRoute"], str
|
||||
] = self.generate_unique_id_function.value
|
||||
else:
|
||||
resolved_generate_unique_id = self.generate_unique_id_function
|
||||
self.unique_id = self.operation_id or resolved_generate_unique_id(self)
|
||||
|
||||
if self.response_model:
|
||||
assert (
|
||||
self.status_code not in STATUS_CODES_WITH_NO_BODY
|
||||
), f"Status code {self.status_code} must not have a response body"
|
||||
status_code not in STATUS_CODES_WITH_NO_BODY
|
||||
), f"Status code {status_code} must not have a response body"
|
||||
response_name = "Response_" + self.unique_id
|
||||
self.response_field = create_response_field(
|
||||
name=response_name, type_=self.response_model
|
||||
@@ -499,7 +397,14 @@ class APIRoute(routing.Route):
|
||||
else:
|
||||
self.response_field = None # type: ignore
|
||||
self.secure_cloned_response_field = None
|
||||
|
||||
if dependencies:
|
||||
self.dependencies = list(dependencies)
|
||||
else:
|
||||
self.dependencies = []
|
||||
self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
|
||||
# if a "form feed" character (page break) is found in the description text,
|
||||
# truncate description text to the content preceding the first "form feed"
|
||||
self.description = self.description.split("\f")[0]
|
||||
response_fields = {}
|
||||
for additional_status_code, response in self.responses.items():
|
||||
assert isinstance(response, dict), "An additional response must be a dict"
|
||||
@@ -516,50 +421,16 @@ class APIRoute(routing.Route):
|
||||
else:
|
||||
self.response_fields = {}
|
||||
|
||||
self.dependant = get_dependant(
|
||||
path=self._route_full_path_format, call=self.endpoint
|
||||
)
|
||||
assert callable(endpoint), "An endpoint must be a callable"
|
||||
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
|
||||
for depends in self.dependencies[::-1]:
|
||||
self.dependant.dependencies.insert(
|
||||
0,
|
||||
get_parameterless_sub_dependant(
|
||||
depends=depends, path=self._route_full_path_format
|
||||
),
|
||||
get_parameterless_sub_dependant(depends=depends, path=self.path_format),
|
||||
)
|
||||
self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id)
|
||||
self.app = request_response(self.get_route_handler())
|
||||
|
||||
def copy(self: APIRouteType) -> APIRouteType:
|
||||
return type(self)(
|
||||
path=self.path,
|
||||
endpoint=self.endpoint,
|
||||
response_model=self.response_model,
|
||||
status_code=self.status_code,
|
||||
tags=self._route_tags,
|
||||
dependencies=self._route_dependencies,
|
||||
summary=self.summary,
|
||||
description=self.description,
|
||||
response_description=self.response_description,
|
||||
responses=self._route_responses,
|
||||
deprecated=self._route_deprecated,
|
||||
name=self.name,
|
||||
methods=self.methods,
|
||||
operation_id=self.operation_id,
|
||||
response_model_include=self.response_model_include,
|
||||
response_model_exclude=self.response_model_exclude,
|
||||
response_model_by_alias=self.response_model_by_alias,
|
||||
response_model_exclude_unset=self.response_model_exclude_unset,
|
||||
response_model_exclude_defaults=self.response_model_exclude_defaults,
|
||||
response_model_exclude_none=self.response_model_exclude_none,
|
||||
include_in_schema=self._route_include_in_schema,
|
||||
response_class=self._route_response_class,
|
||||
dependency_overrides_provider=self.dependency_overrides_provider,
|
||||
callbacks=self._route_callbacks,
|
||||
openapi_extra=self.openapi_extra,
|
||||
generate_unique_id_function=self._route_generate_unique_id_function,
|
||||
router=self.router,
|
||||
)
|
||||
|
||||
def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
|
||||
return get_request_handler(
|
||||
dependant=self.dependant,
|
||||
@@ -605,7 +476,6 @@ class APIRouter(routing.Router):
|
||||
generate_unique_id_function: Callable[[APIRoute], str] = Default(
|
||||
generate_unique_id
|
||||
),
|
||||
parent_router: Optional["APIRouter"] = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
routes=routes, # type: ignore # in Starlette
|
||||
@@ -620,151 +490,16 @@ class APIRouter(routing.Router):
|
||||
"/"
|
||||
), "A path prefix must not end with '/', as the routes will start with '/'"
|
||||
self.prefix = prefix
|
||||
self.tags: List[Union[str, Enum]] = tags or []
|
||||
self.dependencies = list(dependencies or []) or []
|
||||
self.deprecated = deprecated
|
||||
self.include_in_schema = include_in_schema
|
||||
self.responses = responses or {}
|
||||
self.callbacks = callbacks or []
|
||||
self.dependency_overrides_provider = dependency_overrides_provider
|
||||
self.route_class = route_class
|
||||
|
||||
self.parent_router = parent_router
|
||||
|
||||
# Attributes set in router used to compute resolved attributes
|
||||
self._router_dependencies = list(dependencies or []) or []
|
||||
self._router_generate_unique_id_function = generate_unique_id_function
|
||||
self._router_responses = responses or {}
|
||||
self._router_default_response_class = default_response_class
|
||||
self._router_tags: List[Union[str, Enum]] = tags or []
|
||||
self._router_callbacks = callbacks or []
|
||||
self._router_deprecated = deprecated
|
||||
self._router_include_in_schema = include_in_schema
|
||||
self._router_has_empty_route = False
|
||||
self._router_has_root_route = False
|
||||
self.setup()
|
||||
|
||||
def setup(self) -> None:
|
||||
# setup full path
|
||||
self._router_full_path = self.prefix
|
||||
if self.parent_router:
|
||||
self._router_full_path = self.parent_router._router_full_path + self.prefix
|
||||
# setup dependencies
|
||||
self.dependencies: List[params.Depends] = []
|
||||
if self.parent_router:
|
||||
self.dependencies.extend(self.parent_router.dependencies)
|
||||
self.dependencies.extend(self._router_dependencies)
|
||||
|
||||
# setup generate_unique_id
|
||||
generate_unique_id_functions: List[
|
||||
Union[Callable[[APIRoute], str], DefaultPlaceholder]
|
||||
] = [self._router_generate_unique_id_function]
|
||||
if self.parent_router:
|
||||
generate_unique_id_functions.append(
|
||||
self.parent_router.generate_unique_id_function
|
||||
)
|
||||
current_generate_unique_id_function = get_value_or_default(
|
||||
*generate_unique_id_functions
|
||||
)
|
||||
self.generate_unique_id_function: Union[
|
||||
Callable[[APIRoute], str], DefaultPlaceholder
|
||||
] = current_generate_unique_id_function
|
||||
|
||||
# setup responses
|
||||
responses: Dict[Union[int, str], Dict[str, Any]] = {}
|
||||
if self.parent_router:
|
||||
responses.update(self.parent_router.responses)
|
||||
responses.update(self._router_responses)
|
||||
self.responses: Dict[Union[int, str], Dict[str, Any]] = responses
|
||||
|
||||
# setup default_response_class
|
||||
default_response_classes: List[Union[Type[Response], DefaultPlaceholder]] = [
|
||||
self._router_default_response_class
|
||||
]
|
||||
if self.parent_router:
|
||||
default_response_classes.append(self.parent_router.default_response_class)
|
||||
current_default_response_class = get_value_or_default(*default_response_classes)
|
||||
self.default_response_class: Union[
|
||||
Type[Response], DefaultPlaceholder
|
||||
] = current_default_response_class
|
||||
|
||||
# setup tags
|
||||
self.tags: List[Union[str, Enum]] = []
|
||||
if self.parent_router:
|
||||
self.tags.extend(self.parent_router.tags)
|
||||
self.tags.extend(self._router_tags)
|
||||
|
||||
# setup callbacks
|
||||
self.callbacks: List[BaseRoute] = []
|
||||
if self.parent_router:
|
||||
self.callbacks.extend(self.parent_router.callbacks)
|
||||
self.callbacks.extend(self._router_callbacks)
|
||||
|
||||
# setup deprecated
|
||||
self.deprecated = self._router_deprecated
|
||||
if self.parent_router:
|
||||
self.deprecated = self._router_deprecated or self.parent_router.deprecated
|
||||
|
||||
# setup include_in_schema
|
||||
self.include_in_schema = self._router_include_in_schema
|
||||
if self.parent_router:
|
||||
self.include_in_schema = (
|
||||
self._router_include_in_schema and self.parent_router.include_in_schema
|
||||
)
|
||||
|
||||
# setup routes
|
||||
for route in self.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
route.router = self
|
||||
route.setup()
|
||||
elif isinstance(route, APIMount):
|
||||
route.parent_router = self
|
||||
route.setup()
|
||||
|
||||
def copy(self: APIRouterType) -> APIRouterType:
|
||||
routes: List[routing.BaseRoute] = []
|
||||
for route in self.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
routes.append(route.copy())
|
||||
elif isinstance(route, APIMount):
|
||||
routes.append(route.copy())
|
||||
else:
|
||||
routes.append(route)
|
||||
copied_router = type(self)(
|
||||
prefix=self.prefix,
|
||||
tags=self._router_tags,
|
||||
dependencies=self._router_dependencies,
|
||||
default_response_class=self._router_default_response_class,
|
||||
responses=self._router_responses,
|
||||
callbacks=self._router_callbacks,
|
||||
routes=routes,
|
||||
redirect_slashes=self.redirect_slashes,
|
||||
default=self.default,
|
||||
dependency_overrides_provider=self.dependency_overrides_provider,
|
||||
route_class=self.route_class,
|
||||
on_startup=self.on_startup,
|
||||
on_shutdown=self.on_shutdown,
|
||||
deprecated=self._router_deprecated,
|
||||
include_in_schema=self._router_include_in_schema,
|
||||
generate_unique_id_function=self._router_generate_unique_id_function,
|
||||
parent_router=self.parent_router,
|
||||
)
|
||||
copied_router._router_has_empty_route = self._router_has_empty_route
|
||||
copied_router._router_has_root_route = self._router_has_root_route
|
||||
for route in copied_router.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
route.router = copied_router
|
||||
route.setup()
|
||||
elif isinstance(route, Mount):
|
||||
if isinstance(route.app, APIRouter):
|
||||
route.app.setup()
|
||||
return copied_router
|
||||
|
||||
def iter_all_routes(self) -> Iterator[routing.BaseRoute]:
|
||||
for route in self.routes:
|
||||
if isinstance(route, Mount):
|
||||
if isinstance(route.app, APIRouter):
|
||||
yield from route.app.iter_all_routes()
|
||||
else:
|
||||
yield route
|
||||
|
||||
def api_mount(self, router: "APIRouter", name: Optional[str] = None) -> None:
|
||||
route = APIMount(router=router, name=name, parent_router=self)
|
||||
self.routes.append(route)
|
||||
self.default_response_class = default_response_class
|
||||
self.generate_unique_id_function = generate_unique_id_function
|
||||
|
||||
def add_api_route(
|
||||
self,
|
||||
@@ -802,18 +537,34 @@ class APIRouter(routing.Router):
|
||||
) -> None:
|
||||
route_class = route_class_override or self.route_class
|
||||
responses = responses or {}
|
||||
combined_responses = {**self.responses, **responses}
|
||||
current_response_class = get_value_or_default(
|
||||
response_class, self.default_response_class
|
||||
)
|
||||
current_tags = self.tags.copy()
|
||||
if tags:
|
||||
current_tags.extend(tags)
|
||||
current_dependencies = self.dependencies.copy()
|
||||
if dependencies:
|
||||
current_dependencies.extend(dependencies)
|
||||
current_callbacks = self.callbacks.copy()
|
||||
if callbacks:
|
||||
current_callbacks.extend(callbacks)
|
||||
current_generate_unique_id = get_value_or_default(
|
||||
generate_unique_id_function, self.generate_unique_id_function
|
||||
)
|
||||
route = route_class(
|
||||
path,
|
||||
self.prefix + path,
|
||||
endpoint=endpoint,
|
||||
response_model=response_model,
|
||||
status_code=status_code,
|
||||
tags=tags,
|
||||
dependencies=dependencies,
|
||||
tags=current_tags,
|
||||
dependencies=current_dependencies,
|
||||
summary=summary,
|
||||
description=description,
|
||||
response_description=response_description,
|
||||
responses=responses,
|
||||
deprecated=deprecated,
|
||||
responses=combined_responses,
|
||||
deprecated=deprecated or self.deprecated,
|
||||
methods=methods,
|
||||
operation_id=operation_id,
|
||||
response_model_include=response_model_include,
|
||||
@@ -822,20 +573,15 @@ class APIRouter(routing.Router):
|
||||
response_model_exclude_unset=response_model_exclude_unset,
|
||||
response_model_exclude_defaults=response_model_exclude_defaults,
|
||||
response_model_exclude_none=response_model_exclude_none,
|
||||
include_in_schema=include_in_schema,
|
||||
response_class=response_class,
|
||||
include_in_schema=include_in_schema and self.include_in_schema,
|
||||
response_class=current_response_class,
|
||||
name=name,
|
||||
dependency_overrides_provider=self.dependency_overrides_provider,
|
||||
callbacks=callbacks,
|
||||
callbacks=current_callbacks,
|
||||
openapi_extra=openapi_extra,
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
router=self,
|
||||
generate_unique_id_function=current_generate_unique_id,
|
||||
)
|
||||
self.routes.append(route)
|
||||
if not path:
|
||||
self._router_has_empty_route = True
|
||||
if path == "/":
|
||||
self._router_has_root_route = True
|
||||
|
||||
def api_route(
|
||||
self,
|
||||
@@ -903,7 +649,7 @@ class APIRouter(routing.Router):
|
||||
self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
|
||||
) -> None:
|
||||
route = APIWebSocketRoute(
|
||||
path,
|
||||
self.prefix + path,
|
||||
endpoint=endpoint,
|
||||
name=name,
|
||||
dependency_overrides_provider=self.dependency_overrides_provider,
|
||||
@@ -934,197 +680,103 @@ class APIRouter(routing.Router):
|
||||
generate_unique_id_function: Callable[[APIRoute], str] = Default(
|
||||
generate_unique_id
|
||||
),
|
||||
copy_flat_routes: Optional[bool] = None,
|
||||
) -> None:
|
||||
if prefix:
|
||||
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
||||
assert not prefix.endswith(
|
||||
"/"
|
||||
), "A path prefix must not end with '/', as the routes will start with '/'"
|
||||
resolved_copy_flat_routes = copy_flat_routes
|
||||
if resolved_copy_flat_routes is None:
|
||||
resolved_copy_flat_routes = not (prefix or router.prefix)
|
||||
if not resolved_copy_flat_routes:
|
||||
included_router = router.copy()
|
||||
if (
|
||||
prefix
|
||||
or tags
|
||||
or dependencies
|
||||
or not isinstance(default_response_class, DefaultPlaceholder)
|
||||
or responses
|
||||
or callbacks
|
||||
or deprecated is not None
|
||||
or include_in_schema is not True
|
||||
or not isinstance(generate_unique_id_function, DefaultPlaceholder)
|
||||
):
|
||||
current_router = type(self)(
|
||||
prefix=prefix,
|
||||
tags=tags,
|
||||
dependencies=dependencies,
|
||||
default_response_class=default_response_class,
|
||||
responses=responses,
|
||||
callbacks=callbacks,
|
||||
deprecated=deprecated,
|
||||
include_in_schema=include_in_schema,
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
parent_router=self,
|
||||
)
|
||||
# current_router.api_mount(included_router)
|
||||
current_router.include_router(included_router)
|
||||
if included_router._router_has_empty_route and not self.prefix:
|
||||
current_router._router_has_empty_route = True
|
||||
current_router._router_has_root_route = (
|
||||
included_router._router_has_root_route
|
||||
)
|
||||
self.api_mount(current_router)
|
||||
included_router.parent_router = current_router
|
||||
else:
|
||||
self.api_mount(included_router)
|
||||
included_router.parent_router = self
|
||||
|
||||
included_router.setup()
|
||||
else:
|
||||
# TODO: remove this and its test, as a subrouter can mount another
|
||||
# subrouter (done automatically of other things are overwritten) and both
|
||||
# can omit a prefix, this would error out
|
||||
# for r in router.routes:
|
||||
# path = getattr(r, "path")
|
||||
# name = getattr(r, "name", "unknown")
|
||||
# if path is not None and not path:
|
||||
# raise Exception(
|
||||
# f"Prefix and path cannot be both empty (path operation: {name})"
|
||||
# )
|
||||
if responses is None:
|
||||
responses = {}
|
||||
for route in router.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
combined_responses = {}
|
||||
if route.router:
|
||||
combined_responses.update(route.router.responses)
|
||||
combined_responses.update(responses)
|
||||
combined_responses.update(route.responses)
|
||||
|
||||
response_classes: List[
|
||||
Union[Type[Response], DefaultPlaceholder]
|
||||
] = []
|
||||
if route.router:
|
||||
response_classes.append(route.router.default_response_class)
|
||||
response_classes.extend(
|
||||
[
|
||||
route.response_class,
|
||||
router.default_response_class,
|
||||
default_response_class,
|
||||
self.default_response_class,
|
||||
]
|
||||
for r in router.routes:
|
||||
path = getattr(r, "path")
|
||||
name = getattr(r, "name", "unknown")
|
||||
if path is not None and not path:
|
||||
raise Exception(
|
||||
f"Prefix and path cannot be both empty (path operation: {name})"
|
||||
)
|
||||
use_response_class = get_value_or_default(*response_classes)
|
||||
current_tags = []
|
||||
if route.router:
|
||||
current_tags.extend(route.router.tags)
|
||||
if tags:
|
||||
current_tags.extend(tags)
|
||||
if route.tags:
|
||||
current_tags.extend(route.tags)
|
||||
current_dependencies: List[params.Depends] = []
|
||||
if route.router:
|
||||
current_dependencies.extend(route.router.dependencies)
|
||||
if dependencies:
|
||||
current_dependencies.extend(dependencies)
|
||||
if route.dependencies:
|
||||
current_dependencies.extend(route.dependencies)
|
||||
current_callbacks = []
|
||||
if route.router:
|
||||
current_callbacks.extend(route.router.callbacks)
|
||||
if callbacks:
|
||||
current_callbacks.extend(callbacks)
|
||||
if route.callbacks:
|
||||
current_callbacks.extend(route.callbacks)
|
||||
|
||||
generate_unique_id_functions: List[
|
||||
Union[Callable[[APIRoute], str], DefaultPlaceholder]
|
||||
] = []
|
||||
if route.router:
|
||||
generate_unique_id_functions.append(
|
||||
route.router.generate_unique_id_function
|
||||
)
|
||||
generate_unique_id_functions.extend(
|
||||
[
|
||||
route.generate_unique_id_function,
|
||||
router.generate_unique_id_function,
|
||||
generate_unique_id_function,
|
||||
self.generate_unique_id_function,
|
||||
]
|
||||
)
|
||||
current_generate_unique_id_function = get_value_or_default(
|
||||
*generate_unique_id_functions
|
||||
)
|
||||
path = prefix + route.path
|
||||
if route.router:
|
||||
path = prefix + route.router.prefix + path
|
||||
self.add_api_route(
|
||||
path,
|
||||
route.endpoint,
|
||||
response_model=route.response_model,
|
||||
status_code=route.status_code,
|
||||
tags=current_tags,
|
||||
dependencies=current_dependencies,
|
||||
summary=route.summary,
|
||||
description=route.description,
|
||||
response_description=route.response_description,
|
||||
responses=combined_responses,
|
||||
deprecated=route.deprecated or deprecated or self.deprecated,
|
||||
methods=route.methods,
|
||||
operation_id=route.operation_id,
|
||||
response_model_include=route.response_model_include,
|
||||
response_model_exclude=route.response_model_exclude,
|
||||
response_model_by_alias=route.response_model_by_alias,
|
||||
response_model_exclude_unset=route.response_model_exclude_unset,
|
||||
response_model_exclude_defaults=route.response_model_exclude_defaults,
|
||||
response_model_exclude_none=route.response_model_exclude_none,
|
||||
include_in_schema=route.include_in_schema
|
||||
and self.include_in_schema
|
||||
and include_in_schema,
|
||||
response_class=use_response_class,
|
||||
name=route.name,
|
||||
route_class_override=type(route),
|
||||
callbacks=current_callbacks,
|
||||
openapi_extra=route.openapi_extra,
|
||||
generate_unique_id_function=current_generate_unique_id_function,
|
||||
)
|
||||
elif isinstance(route, APIMount):
|
||||
self.include_router(
|
||||
route.app,
|
||||
prefix=prefix,
|
||||
tags=tags,
|
||||
dependencies=dependencies,
|
||||
default_response_class=default_response_class,
|
||||
responses=responses,
|
||||
callbacks=callbacks,
|
||||
deprecated=deprecated,
|
||||
include_in_schema=include_in_schema,
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
)
|
||||
elif isinstance(route, routing.Route):
|
||||
methods = list(route.methods or []) # type: ignore # in Starlette
|
||||
self.add_route(
|
||||
prefix + route.path,
|
||||
route.endpoint,
|
||||
methods=methods,
|
||||
include_in_schema=route.include_in_schema,
|
||||
name=route.name,
|
||||
)
|
||||
elif isinstance(route, APIWebSocketRoute):
|
||||
self.add_api_websocket_route(
|
||||
prefix + route.path, route.endpoint, name=route.name
|
||||
)
|
||||
elif isinstance(route, routing.WebSocketRoute):
|
||||
self.add_websocket_route(
|
||||
prefix + route.path, route.endpoint, name=route.name
|
||||
)
|
||||
for handler in router.on_startup:
|
||||
self.add_event_handler("startup", handler)
|
||||
for handler in router.on_shutdown:
|
||||
self.add_event_handler("shutdown", handler)
|
||||
if responses is None:
|
||||
responses = {}
|
||||
for route in router.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
combined_responses = {**responses, **route.responses}
|
||||
use_response_class = get_value_or_default(
|
||||
route.response_class,
|
||||
router.default_response_class,
|
||||
default_response_class,
|
||||
self.default_response_class,
|
||||
)
|
||||
current_tags = []
|
||||
if tags:
|
||||
current_tags.extend(tags)
|
||||
if route.tags:
|
||||
current_tags.extend(route.tags)
|
||||
current_dependencies: List[params.Depends] = []
|
||||
if dependencies:
|
||||
current_dependencies.extend(dependencies)
|
||||
if route.dependencies:
|
||||
current_dependencies.extend(route.dependencies)
|
||||
current_callbacks = []
|
||||
if callbacks:
|
||||
current_callbacks.extend(callbacks)
|
||||
if route.callbacks:
|
||||
current_callbacks.extend(route.callbacks)
|
||||
current_generate_unique_id = get_value_or_default(
|
||||
route.generate_unique_id_function,
|
||||
router.generate_unique_id_function,
|
||||
generate_unique_id_function,
|
||||
self.generate_unique_id_function,
|
||||
)
|
||||
self.add_api_route(
|
||||
prefix + route.path,
|
||||
route.endpoint,
|
||||
response_model=route.response_model,
|
||||
status_code=route.status_code,
|
||||
tags=current_tags,
|
||||
dependencies=current_dependencies,
|
||||
summary=route.summary,
|
||||
description=route.description,
|
||||
response_description=route.response_description,
|
||||
responses=combined_responses,
|
||||
deprecated=route.deprecated or deprecated or self.deprecated,
|
||||
methods=route.methods,
|
||||
operation_id=route.operation_id,
|
||||
response_model_include=route.response_model_include,
|
||||
response_model_exclude=route.response_model_exclude,
|
||||
response_model_by_alias=route.response_model_by_alias,
|
||||
response_model_exclude_unset=route.response_model_exclude_unset,
|
||||
response_model_exclude_defaults=route.response_model_exclude_defaults,
|
||||
response_model_exclude_none=route.response_model_exclude_none,
|
||||
include_in_schema=route.include_in_schema
|
||||
and self.include_in_schema
|
||||
and include_in_schema,
|
||||
response_class=use_response_class,
|
||||
name=route.name,
|
||||
route_class_override=type(route),
|
||||
callbacks=current_callbacks,
|
||||
openapi_extra=route.openapi_extra,
|
||||
generate_unique_id_function=current_generate_unique_id,
|
||||
)
|
||||
elif isinstance(route, routing.Route):
|
||||
methods = list(route.methods or []) # type: ignore # in Starlette
|
||||
self.add_route(
|
||||
prefix + route.path,
|
||||
route.endpoint,
|
||||
methods=methods,
|
||||
include_in_schema=route.include_in_schema,
|
||||
name=route.name,
|
||||
)
|
||||
elif isinstance(route, APIWebSocketRoute):
|
||||
self.add_api_websocket_route(
|
||||
prefix + route.path, route.endpoint, name=route.name
|
||||
)
|
||||
elif isinstance(route, routing.WebSocketRoute):
|
||||
self.add_websocket_route(
|
||||
prefix + route.path, route.endpoint, name=route.name
|
||||
)
|
||||
for handler in router.on_startup:
|
||||
self.add_event_handler("startup", handler)
|
||||
for handler in router.on_shutdown:
|
||||
self.add_event_handler("shutdown", handler)
|
||||
|
||||
def get(
|
||||
self,
|
||||
@@ -1574,100 +1226,3 @@ class APIRouter(routing.Router):
|
||||
openapi_extra=openapi_extra,
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
)
|
||||
|
||||
|
||||
class APIMount(routing.Mount):
|
||||
def __init__(
|
||||
self,
|
||||
router: APIRouter,
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
parent_router: Optional[APIRouter] = None,
|
||||
) -> None:
|
||||
self.name = name # type: ignore # in Starlette
|
||||
self.parent_router = parent_router
|
||||
self.router = router
|
||||
|
||||
self.setup()
|
||||
|
||||
def setup(self) -> None:
|
||||
self.app: APIRouter = self.router.copy()
|
||||
if self.parent_router:
|
||||
self.app.parent_router = self.parent_router
|
||||
self.app.setup()
|
||||
self.path = self.app.prefix
|
||||
self.path_regex, self.path_format, self.param_convertors = compile_path(
|
||||
self.path + "/{path:path}"
|
||||
)
|
||||
|
||||
# Add custom additional root without trailing slash for compatibility with
|
||||
# include_router and possibly app migrations
|
||||
# Ref: https://github.com/tiangolo/fastapi/issues/414
|
||||
(
|
||||
self._root_path_regex,
|
||||
self._root_path_format,
|
||||
self._root_param_convertors,
|
||||
) = compile_path(self.path)
|
||||
(
|
||||
self._root_path_regex_trailing,
|
||||
self._root_path_format_trailing,
|
||||
self._root_param_convertors_trailing,
|
||||
) = compile_path(self.path + "/")
|
||||
|
||||
def copy(self: APIMountType) -> APIMountType:
|
||||
return type(self)(
|
||||
router=self.router.copy(),
|
||||
name=self.name,
|
||||
parent_router=self.parent_router,
|
||||
)
|
||||
|
||||
def matches(self, scope: Scope) -> Tuple[Match, Scope]:
|
||||
if scope["type"] in ("http", "websocket"):
|
||||
path = scope["path"]
|
||||
if self.app._router_has_empty_route:
|
||||
# Custom logic to support paths without trailing slash
|
||||
# Ref: https://github.com/tiangolo/fastapi/issues/414
|
||||
# This mixes the code in
|
||||
# starlette.routing.Route.matches() and starlette.routing.Mount.matches()
|
||||
match = self._root_path_regex.match(path)
|
||||
if match:
|
||||
matched_params = match.groupdict()
|
||||
for key, value in matched_params.items():
|
||||
matched_params[key] = self.param_convertors[key].convert(value)
|
||||
path_params = dict(scope.get("path_params", {}))
|
||||
path_params.update(matched_params)
|
||||
root_path = scope.get("root_path", "")
|
||||
child_scope = {
|
||||
"path_params": path_params,
|
||||
"app_root_path": scope.get("app_root_path", root_path),
|
||||
"root_path": root_path,
|
||||
"path": "",
|
||||
"endpoint": self.app,
|
||||
}
|
||||
return Match.FULL, child_scope
|
||||
if not self.app._router_has_root_route:
|
||||
match = self._root_path_regex_trailing.match(path)
|
||||
if match:
|
||||
return Match.NONE, {}
|
||||
# End of custom logic
|
||||
# Duplicated code from Starlette
|
||||
match = self.path_regex.match(path)
|
||||
if match:
|
||||
matched_params = match.groupdict()
|
||||
for key, value in matched_params.items():
|
||||
matched_params[key] = self.param_convertors[key].convert(value)
|
||||
remaining_path = "/" + matched_params.pop("path")
|
||||
matched_path = path[: -len(remaining_path)]
|
||||
path_params = dict(scope.get("path_params", {}))
|
||||
path_params.update(matched_params)
|
||||
root_path = scope.get("root_path", "")
|
||||
child_scope = {
|
||||
"path_params": path_params,
|
||||
"app_root_path": scope.get("app_root_path", root_path),
|
||||
"root_path": root_path + matched_path,
|
||||
"path": remaining_path,
|
||||
"endpoint": self.app,
|
||||
}
|
||||
return Match.FULL, child_scope
|
||||
return Match.NONE, {}
|
||||
# End of duplicated code from Starlette
|
||||
|
||||
@@ -139,7 +139,7 @@ def generate_operation_id_for_path(
|
||||
|
||||
|
||||
def generate_unique_id(route: "APIRoute") -> str:
|
||||
operation_id = route.name + route._route_full_path_format
|
||||
operation_id = route.name + route.path_format
|
||||
operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id)
|
||||
assert route.methods
|
||||
operation_id = operation_id + "_" + list(route.methods)[0].lower()
|
||||
|
||||
@@ -59,15 +59,15 @@ test = [
|
||||
"peewee >=3.13.3,<4.0.0",
|
||||
"databases[sqlite] >=0.3.2,<0.6.0",
|
||||
"orjson >=3.2.1,<4.0.0",
|
||||
"ujson >=4.0.1,<5.0.0",
|
||||
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0",
|
||||
"python-multipart >=0.0.5,<0.0.6",
|
||||
"flask >=1.1.2,<3.0.0",
|
||||
"anyio[trio] >=3.2.1,<4.0.0",
|
||||
|
||||
# types
|
||||
"types-ujson ==0.1.1",
|
||||
"types-orjson ==3.6.0",
|
||||
"types-dataclasses ==0.1.7; python_version<'3.7'",
|
||||
"types-ujson ==4.2.1",
|
||||
"types-orjson ==3.6.2",
|
||||
"types-dataclasses ==0.6.5; python_version<'3.7'",
|
||||
]
|
||||
doc = [
|
||||
"mkdocs >=1.1.2,<2.0.0",
|
||||
@@ -77,25 +77,25 @@ doc = [
|
||||
# TODO: upgrade and enable typer-cli once it supports Click 8.x.x
|
||||
# "typer-cli >=0.0.12,<0.0.13",
|
||||
"typer >=0.4.1,<0.5.0",
|
||||
"pyyaml >=5.3.1,<6.0.0"
|
||||
"pyyaml >=5.3.1,<7.0.0",
|
||||
]
|
||||
dev = [
|
||||
"python-jose[cryptography] >=3.3.0,<4.0.0",
|
||||
"passlib[bcrypt] >=1.7.2,<2.0.0",
|
||||
"autoflake >=1.4.0,<2.0.0",
|
||||
"flake8 >=3.8.3,<4.0.0",
|
||||
"uvicorn[standard] >=0.12.0,<0.16.0",
|
||||
"uvicorn[standard] >=0.12.0,<0.18.0",
|
||||
]
|
||||
all = [
|
||||
"requests >=2.24.0,<3.0.0",
|
||||
"jinja2 >=2.11.2,<4.0.0",
|
||||
"python-multipart >=0.0.5,<0.0.6",
|
||||
"itsdangerous >=1.1.0,<3.0.0",
|
||||
"pyyaml >=5.3.1,<6.0.0",
|
||||
"ujson >=4.0.1,<5.0.0",
|
||||
"pyyaml >=5.3.1,<7.0.0",
|
||||
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0",
|
||||
"orjson >=3.2.1,<4.0.0",
|
||||
"email_validator >=1.1.1,<2.0.0",
|
||||
"uvicorn[standard] >=0.12.0,<0.16.0",
|
||||
"uvicorn[standard] >=0.12.0,<0.18.0",
|
||||
]
|
||||
|
||||
[tool.isort]
|
||||
|
||||
@@ -76,7 +76,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -119,7 +119,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -54,7 +54,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -1101,7 +1101,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -2,6 +2,7 @@ import pytest
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.testclient import TestClient
|
||||
from starlette.routing import Route
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -106,9 +107,9 @@ def test_get_path(path, expected_status, expected_response):
|
||||
|
||||
def test_route_classes():
|
||||
routes = {}
|
||||
for r in app.router.iter_all_routes():
|
||||
if isinstance(r, APIRoute):
|
||||
routes[r._route_full_path_format] = r
|
||||
for r in app.router.routes:
|
||||
assert isinstance(r, Route)
|
||||
routes[r.path] = r
|
||||
assert getattr(routes["/a/"], "x_type") == "A"
|
||||
assert getattr(routes["/a/b/"], "x_type") == "B"
|
||||
assert getattr(routes["/a/b/c/"], "x_type") == "C"
|
||||
|
||||
@@ -177,7 +177,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -292,7 +292,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -116,7 +116,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -217,7 +217,9 @@ def test_top_level_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -416,7 +418,9 @@ def test_router_overrides_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -615,7 +619,9 @@ def test_router_include_overrides_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -887,7 +893,9 @@ def test_subrouter_top_level_include_overrides_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -1089,7 +1097,9 @@ def test_router_path_operation_overrides_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -1295,7 +1305,9 @@ def test_app_path_operation_overrides_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -1579,7 +1591,9 @@ def test_callback_override_generate_unique_id():
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}]
|
||||
},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -85,7 +85,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -6612,7 +6612,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -101,7 +101,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -79,7 +79,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -63,7 +63,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -71,7 +71,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -149,7 +149,7 @@ openapi_shema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -57,7 +57,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -36,7 +36,7 @@ schema = {
|
||||
"ValidationError": {
|
||||
"properties": {
|
||||
"loc": {
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
},
|
||||
|
||||
@@ -830,7 +830,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -117,7 +117,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -121,7 +121,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -122,7 +122,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -102,7 +102,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -256,7 +256,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -200,7 +200,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -76,7 +76,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -72,7 +72,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -77,7 +77,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -75,7 +75,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -88,7 +88,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -323,7 +323,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -63,7 +63,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -61,7 +61,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -87,7 +87,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -84,7 +84,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -79,7 +79,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -77,7 +77,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -90,7 +90,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -88,7 +88,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -53,7 +53,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -52,7 +52,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -109,7 +109,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -108,7 +108,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -108,7 +108,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -50,7 +50,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -48,7 +48,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -71,7 +71,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -118,7 +118,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -104,7 +104,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -102,7 +102,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -62,7 +62,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -60,7 +60,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -55,7 +55,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -102,7 +102,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -47,7 +47,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -89,7 +89,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -87,7 +87,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -78,7 +78,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -77,7 +77,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -147,7 +147,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -49,7 +49,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -49,7 +49,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -49,7 +49,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -49,7 +49,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -69,7 +69,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -49,7 +49,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -51,7 +51,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -48,7 +48,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -143,7 +143,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -72,7 +72,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -72,7 +72,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -71,7 +71,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -71,7 +71,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -49,7 +49,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -54,7 +54,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
@@ -138,7 +138,7 @@ openapi_schema2 = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -56,7 +56,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -68,7 +68,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -66,7 +66,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -59,7 +59,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -57,7 +57,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -53,7 +53,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -52,7 +52,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -52,7 +52,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
@@ -54,7 +54,7 @@ openapi_schema = {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user