mirror of https://github.com/tiangolo/fastapi.git
Additional Responses implementation
This commit is contained in:
parent
9778542ba6
commit
aa0bca7bb2
|
|
@ -3,6 +3,7 @@ from typing import Any, Callable, Dict, List, Optional, Type
|
||||||
from fastapi import routing
|
from fastapi import routing
|
||||||
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
|
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
|
||||||
from fastapi.openapi.utils import get_openapi
|
from fastapi.openapi.utils import get_openapi
|
||||||
|
from fastapi.openapi.models import AdditionalResponse, AdditionalResponseDescription
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
from starlette.exceptions import ExceptionMiddleware, HTTPException
|
from starlette.exceptions import ExceptionMiddleware, HTTPException
|
||||||
|
|
@ -104,22 +105,23 @@ class FastAPI(Starlette):
|
||||||
self.add_exception_handler(HTTPException, http_exception)
|
self.add_exception_handler(HTTPException, http_exception)
|
||||||
|
|
||||||
def add_api_route(
|
def add_api_route(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
endpoint: Callable,
|
endpoint: Callable,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
methods: List[str] = None,
|
deprecated: bool = None,
|
||||||
operation_id: str = None,
|
methods: List[str] = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.router.add_api_route(
|
self.router.add_api_route(
|
||||||
path,
|
path,
|
||||||
|
|
@ -130,6 +132,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=methods,
|
methods=methods,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -139,21 +142,22 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def api_route(
|
def api_route(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
methods: List[str] = None,
|
deprecated: bool = None,
|
||||||
operation_id: str = None,
|
methods: List[str] = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
def decorator(func: Callable) -> Callable:
|
def decorator(func: Callable) -> Callable:
|
||||||
self.router.add_api_route(
|
self.router.add_api_route(
|
||||||
|
|
@ -165,6 +169,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=methods,
|
methods=methods,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -177,25 +182,31 @@ class FastAPI(Starlette):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def include_router(
|
def include_router(
|
||||||
self, router: routing.APIRouter, *, prefix: str = "", tags: List[str] = None
|
self,
|
||||||
|
router: routing.APIRouter,
|
||||||
|
*,
|
||||||
|
prefix: str = "",
|
||||||
|
tags: List[str] = None,
|
||||||
|
additional_responses: AdditionalResponse = [],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.router.include_router(router, prefix=prefix, tags=tags)
|
self.router.include_router(router, prefix=prefix, tags=tags, additional_responses=additional_responses,)
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.get(
|
return self.router.get(
|
||||||
path,
|
path,
|
||||||
|
|
@ -205,6 +216,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -213,20 +225,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def put(
|
def put(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.put(
|
return self.router.put(
|
||||||
path,
|
path,
|
||||||
|
|
@ -236,6 +249,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -244,20 +258,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(
|
def post(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.post(
|
return self.router.post(
|
||||||
path,
|
path,
|
||||||
|
|
@ -267,6 +282,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -275,20 +291,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(
|
def delete(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.delete(
|
return self.router.delete(
|
||||||
path,
|
path,
|
||||||
|
|
@ -298,6 +315,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -306,20 +324,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def options(
|
def options(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.options(
|
return self.router.options(
|
||||||
path,
|
path,
|
||||||
|
|
@ -329,6 +348,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -337,20 +357,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def head(
|
def head(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.head(
|
return self.router.head(
|
||||||
path,
|
path,
|
||||||
|
|
@ -360,6 +381,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -368,20 +390,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def patch(
|
def patch(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.patch(
|
return self.router.patch(
|
||||||
path,
|
path,
|
||||||
|
|
@ -391,6 +414,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
@ -399,20 +423,21 @@ class FastAPI(Starlette):
|
||||||
)
|
)
|
||||||
|
|
||||||
def trace(
|
def trace(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.router.trace(
|
return self.router.trace(
|
||||||
path,
|
path,
|
||||||
|
|
@ -422,6 +447,7 @@ class FastAPI(Starlette):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
include_in_schema=include_in_schema,
|
include_in_schema=include_in_schema,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import logging
|
import logging
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Optional, Union, Type, ClassVar, Callable
|
||||||
|
|
||||||
from pydantic import BaseModel, Schema as PSchema
|
from pydantic import BaseModel, Schema as PSchema
|
||||||
from pydantic.types import UrlStr
|
from pydantic.types import UrlStr
|
||||||
|
from pydantic.fields import Field
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import email_validator
|
import email_validator
|
||||||
|
|
@ -343,6 +344,35 @@ class Tag(BaseModel):
|
||||||
externalDocs: Optional[ExternalDocumentation] = None
|
externalDocs: Optional[ExternalDocumentation] = None
|
||||||
|
|
||||||
|
|
||||||
|
class BaseAdditionalResponse(BaseModel):
|
||||||
|
description: str
|
||||||
|
content_type: str = None
|
||||||
|
|
||||||
|
|
||||||
|
class AdditionalResponse(BaseAdditionalResponse):
|
||||||
|
status_code: int = PSchema(
|
||||||
|
...,
|
||||||
|
ge=100,
|
||||||
|
le=540,
|
||||||
|
title='Status Code',
|
||||||
|
description='HTTP status code',
|
||||||
|
)
|
||||||
|
# NOTE: waiting for pydantic to allow `typing.Type[BasicModel]` type
|
||||||
|
# so, going for `Any` and extra validation on
|
||||||
|
# routing methods
|
||||||
|
models: Optional[List[Any]] = PSchema(
|
||||||
|
[],
|
||||||
|
title='Additional Response Models',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AdditionalResponseDescription(BaseAdditionalResponse):
|
||||||
|
schema_field: Optional[Field] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
arbitrary_types_allowed = True
|
||||||
|
|
||||||
|
|
||||||
class OpenAPI(BaseModel):
|
class OpenAPI(BaseModel):
|
||||||
openapi: str
|
openapi: str
|
||||||
info: Info
|
info: Info
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,26 @@ def get_openapi_path(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
for add_response_code, add_response in route.additional_responses.items():
|
||||||
|
add_response_schema = {}
|
||||||
|
if (add_response.content_type or route.content_type.media_type
|
||||||
|
) == 'application/json' and add_response.schema_field is not None:
|
||||||
|
add_response_schema, _ = field_schema(
|
||||||
|
add_response.schema_field,
|
||||||
|
model_name_map=model_name_map,
|
||||||
|
ref_prefix=REF_PREFIX,
|
||||||
|
)
|
||||||
|
add_content = {
|
||||||
|
add_response.content_type or
|
||||||
|
route.content_type.media_type: {
|
||||||
|
"schema": add_response_schema,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
operation["responses"][str(add_response_code)] = \
|
||||||
|
{
|
||||||
|
"description": add_response.description,
|
||||||
|
"content": add_content,
|
||||||
|
}
|
||||||
path[method.lower()] = operation
|
path[method.lower()] = operation
|
||||||
return path, security_schemes, definitions
|
return path, security_schemes, definitions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Callable, List, Optional, Type
|
from typing import Any, Callable, List, Optional, Type, Dict, Union
|
||||||
|
|
||||||
from fastapi import params
|
from fastapi import params
|
||||||
from fastapi.dependencies.models import Dependant
|
from fastapi.dependencies.models import Dependant
|
||||||
from fastapi.dependencies.utils import get_body_field, get_dependant, solve_dependencies
|
from fastapi.dependencies.utils import get_body_field, get_dependant, solve_dependencies
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.utils import UnconstrainedConfig
|
from fastapi.utils import UnconstrainedConfig
|
||||||
|
from fastapi.openapi.models import AdditionalResponse, AdditionalResponseDescription
|
||||||
from pydantic import BaseModel, Schema
|
from pydantic import BaseModel, Schema
|
||||||
from pydantic.error_wrappers import ErrorWrapper, ValidationError
|
from pydantic.error_wrappers import ErrorWrapper, ValidationError
|
||||||
from pydantic.fields import Field
|
from pydantic.fields import Field
|
||||||
|
|
@ -104,6 +105,7 @@ class APIRoute(routing.Route):
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
|
additional_responses: AdditionalResponse = [],
|
||||||
deprecated: bool = None,
|
deprecated: bool = None,
|
||||||
name: str = None,
|
name: str = None,
|
||||||
methods: List[str] = None,
|
methods: List[str] = None,
|
||||||
|
|
@ -137,6 +139,56 @@ class APIRoute(routing.Route):
|
||||||
self.summary = summary
|
self.summary = summary
|
||||||
self.description = description or self.endpoint.__doc__
|
self.description = description or self.endpoint.__doc__
|
||||||
self.response_description = response_description
|
self.response_description = response_description
|
||||||
|
self.additional_responses: Dict[int, AdditionalResponseDescription] = {}
|
||||||
|
existed_codes = [self.status_code, 422]
|
||||||
|
if isinstance(additional_responses, dict):
|
||||||
|
self.additional_responses = additional_responses.copy()
|
||||||
|
for add_response in additional_responses:
|
||||||
|
if isinstance(add_response, int):
|
||||||
|
continue
|
||||||
|
assert add_response.status_code not in existed_codes, f"(Duplicated Status Code): Response with status code [{add_response.status_code}] already defined!"
|
||||||
|
existed_codes.append(add_response.status_code)
|
||||||
|
response_models = [
|
||||||
|
m for m in\
|
||||||
|
add_response.models
|
||||||
|
]
|
||||||
|
valid_response_models = True
|
||||||
|
try:
|
||||||
|
valid_response_models = all([
|
||||||
|
issubclass(m, BaseModel)
|
||||||
|
for m in response_models
|
||||||
|
])
|
||||||
|
except TypeError as te:
|
||||||
|
valid_response_models = False
|
||||||
|
if not valid_response_models:
|
||||||
|
raise ValueError(
|
||||||
|
"All response models must be "
|
||||||
|
"a subclass of `pydantic.BaseModel` "
|
||||||
|
"model.",
|
||||||
|
)
|
||||||
|
if (add_response.content_type == 'application/json' or lenient_issubclass(
|
||||||
|
content_type, JSONResponse)):
|
||||||
|
if len(response_models):
|
||||||
|
schema_field = Field(
|
||||||
|
name=f'Additional_response_{add_response.status_code}',
|
||||||
|
type_=Union[tuple(response_models)],
|
||||||
|
class_validators=[],
|
||||||
|
default=None,
|
||||||
|
required=False,
|
||||||
|
model_config=UnconstrainedConfig,
|
||||||
|
schema=Schema(None),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
schema_field = None
|
||||||
|
else:
|
||||||
|
schema_field = None
|
||||||
|
add_resp_description = AdditionalResponseDescription(
|
||||||
|
description=add_response.description,
|
||||||
|
content_type=add_response.content_type,
|
||||||
|
schema_field=schema_field,
|
||||||
|
)
|
||||||
|
self.additional_responses[add_response.status_code] = \
|
||||||
|
add_resp_description
|
||||||
self.deprecated = deprecated
|
self.deprecated = deprecated
|
||||||
if methods is None:
|
if methods is None:
|
||||||
methods = ["GET"]
|
methods = ["GET"]
|
||||||
|
|
@ -164,22 +216,23 @@ class APIRoute(routing.Route):
|
||||||
|
|
||||||
class APIRouter(routing.Router):
|
class APIRouter(routing.Router):
|
||||||
def add_api_route(
|
def add_api_route(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
endpoint: Callable,
|
endpoint: Callable,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
methods: List[str] = None,
|
deprecated: bool = None,
|
||||||
operation_id: str = None,
|
methods: List[str] = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
route = APIRoute(
|
route = APIRoute(
|
||||||
path,
|
path,
|
||||||
|
|
@ -190,6 +243,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=methods,
|
methods=methods,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -200,21 +254,22 @@ class APIRouter(routing.Router):
|
||||||
self.routes.append(route)
|
self.routes.append(route)
|
||||||
|
|
||||||
def api_route(
|
def api_route(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
methods: List[str] = None,
|
deprecated: bool = None,
|
||||||
operation_id: str = None,
|
methods: List[str] = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
def decorator(func: Callable) -> Callable:
|
def decorator(func: Callable) -> Callable:
|
||||||
self.add_api_route(
|
self.add_api_route(
|
||||||
|
|
@ -226,6 +281,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=methods,
|
methods=methods,
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -238,7 +294,12 @@ class APIRouter(routing.Router):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def include_router(
|
def include_router(
|
||||||
self, router: "APIRouter", *, prefix: str = "", tags: List[str] = None
|
self,
|
||||||
|
router: "APIRouter",
|
||||||
|
*,
|
||||||
|
prefix: str = "",
|
||||||
|
tags: List[str] = None,
|
||||||
|
additional_responses: AdditionalResponse = [],
|
||||||
) -> None:
|
) -> None:
|
||||||
if prefix:
|
if prefix:
|
||||||
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
||||||
|
|
@ -247,6 +308,53 @@ class APIRouter(routing.Router):
|
||||||
), "A path prefix must not end with '/', as the routes will start with '/'"
|
), "A path prefix must not end with '/', as the routes will start with '/'"
|
||||||
for route in router.routes:
|
for route in router.routes:
|
||||||
if isinstance(route, APIRoute):
|
if isinstance(route, APIRoute):
|
||||||
|
# really ugly hack and repitition
|
||||||
|
prev_add_resp = route.additional_responses
|
||||||
|
existed_codes = [422, route.status_code
|
||||||
|
] + [int(c) for c in prev_add_resp.keys()]
|
||||||
|
for add_response in additional_responses:
|
||||||
|
assert add_response.status_code not in existed_codes, f"(Duplicated Status Code): Response with status code [{add_response.status_code}] already defined!"
|
||||||
|
existed_codes.append(add_response.status_code)
|
||||||
|
response_models = [
|
||||||
|
m for m in\
|
||||||
|
add_response.models
|
||||||
|
]
|
||||||
|
valid_response_models = True
|
||||||
|
try:
|
||||||
|
valid_response_models = all([
|
||||||
|
issubclass(m, BaseModel) for m in response_models
|
||||||
|
])
|
||||||
|
except AttributeError as ae:
|
||||||
|
valid_response_models = False
|
||||||
|
if not valid_response_models:
|
||||||
|
raise ValueError(
|
||||||
|
"All response models must be"
|
||||||
|
"a subclass of `pydantic.BaseModel`"
|
||||||
|
"model."
|
||||||
|
)
|
||||||
|
if (add_response.content_type == 'application/json' or lenient_issubclass(
|
||||||
|
route.content_type, JSONResponse)):
|
||||||
|
if len(response_models):
|
||||||
|
schema_field = Field(
|
||||||
|
name=f'Additional_response_{add_response.status_code}',
|
||||||
|
type_=Union[tuple(response_models)],
|
||||||
|
class_validators=[],
|
||||||
|
default=None,
|
||||||
|
required=False,
|
||||||
|
model_config=UnconstrainedConfig,
|
||||||
|
schema=Schema(None),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
schema_field = None
|
||||||
|
else:
|
||||||
|
schema_field = None
|
||||||
|
add_resp_description = AdditionalResponseDescription(
|
||||||
|
description=add_response.description,
|
||||||
|
content_type=add_response.content_type,
|
||||||
|
schema_field=schema_field,
|
||||||
|
)
|
||||||
|
route.additional_responses[add_response.status_code] = \
|
||||||
|
add_resp_description
|
||||||
self.add_api_route(
|
self.add_api_route(
|
||||||
prefix + route.path,
|
prefix + route.path,
|
||||||
route.endpoint,
|
route.endpoint,
|
||||||
|
|
@ -256,6 +364,7 @@ class APIRouter(routing.Router):
|
||||||
summary=route.summary,
|
summary=route.summary,
|
||||||
description=route.description,
|
description=route.description,
|
||||||
response_description=route.response_description,
|
response_description=route.response_description,
|
||||||
|
additional_responses=route.additional_responses,
|
||||||
deprecated=route.deprecated,
|
deprecated=route.deprecated,
|
||||||
methods=route.methods,
|
methods=route.methods,
|
||||||
operation_id=route.operation_id,
|
operation_id=route.operation_id,
|
||||||
|
|
@ -273,20 +382,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -296,6 +406,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["GET"],
|
methods=["GET"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -305,20 +416,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def put(
|
def put(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -328,6 +440,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["PUT"],
|
methods=["PUT"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -337,20 +450,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(
|
def post(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -360,6 +474,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["POST"],
|
methods=["POST"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -369,20 +484,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(
|
def delete(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -392,6 +508,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["DELETE"],
|
methods=["DELETE"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -401,20 +518,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def options(
|
def options(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -424,6 +542,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["OPTIONS"],
|
methods=["OPTIONS"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -433,20 +552,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def head(
|
def head(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -456,6 +576,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["HEAD"],
|
methods=["HEAD"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -465,20 +586,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def patch(
|
def patch(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -488,6 +610,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["PATCH"],
|
methods=["PATCH"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
@ -497,20 +620,21 @@ class APIRouter(routing.Router):
|
||||||
)
|
)
|
||||||
|
|
||||||
def trace(
|
def trace(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
*,
|
*,
|
||||||
response_model: Type[BaseModel] = None,
|
response_model: Type[BaseModel] = None,
|
||||||
status_code: int = 200,
|
status_code: int = 200,
|
||||||
tags: List[str] = None,
|
tags: List[str] = None,
|
||||||
summary: str = None,
|
summary: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
response_description: str = "Successful Response",
|
response_description: str = "Successful Response",
|
||||||
deprecated: bool = None,
|
additional_responses: AdditionalResponse = [],
|
||||||
operation_id: str = None,
|
deprecated: bool = None,
|
||||||
include_in_schema: bool = True,
|
operation_id: str = None,
|
||||||
content_type: Type[Response] = JSONResponse,
|
include_in_schema: bool = True,
|
||||||
name: str = None,
|
content_type: Type[Response] = JSONResponse,
|
||||||
|
name: str = None,
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
return self.api_route(
|
return self.api_route(
|
||||||
path=path,
|
path=path,
|
||||||
|
|
@ -520,6 +644,7 @@ class APIRouter(routing.Router):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
description=description,
|
description=description,
|
||||||
response_description=response_description,
|
response_description=response_description,
|
||||||
|
additional_responses=additional_responses,
|
||||||
deprecated=deprecated,
|
deprecated=deprecated,
|
||||||
methods=["TRACE"],
|
methods=["TRACE"],
|
||||||
operation_id=operation_id,
|
operation_id=operation_id,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@ def get_flat_models_from_routes(
|
||||||
body_fields_from_routes.append(route.body_field)
|
body_fields_from_routes.append(route.body_field)
|
||||||
if route.response_field:
|
if route.response_field:
|
||||||
responses_from_routes.append(route.response_field)
|
responses_from_routes.append(route.response_field)
|
||||||
|
if route.additional_responses:
|
||||||
|
for _, add_response in route.additional_responses.items():
|
||||||
|
if add_response.schema_field is not None:
|
||||||
|
responses_from_routes.append(
|
||||||
|
add_response.schema_field,
|
||||||
|
)
|
||||||
flat_models = get_flat_models_from_fields(
|
flat_models = get_flat_models_from_fields(
|
||||||
body_fields_from_routes + responses_from_routes
|
body_fields_from_routes + responses_from_routes
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue