Browse Source

Added default error schema to app constructor

Co-authored-by: Leonardo Mendes <leonardom1808@gmail.com>
Co-authored-by: Gustavo Braga <gustavobb@al.insper.edu.br>
pull/4042/head
CaioFauza 4 years ago
parent
commit
75e5770030
  1. 4
      fastapi/applications.py
  2. 4
      fastapi/openapi/models.py
  3. 28
      fastapi/openapi/utils.py

4
fastapi/applications.py

@ -15,6 +15,7 @@ from fastapi.openapi.docs import (
get_swagger_ui_html, get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html, get_swagger_ui_oauth2_redirect_html,
) )
from fastapi.openapi.models import DefaultErrorSchema
from fastapi.openapi.utils import get_openapi from fastapi.openapi.utils import get_openapi
from fastapi.params import Depends from fastapi.params import Depends
from fastapi.types import DecoratedCallable from fastapi.types import DecoratedCallable
@ -62,6 +63,7 @@ class FastAPI(Starlette):
root_path: str = "", root_path: str = "",
root_path_in_servers: bool = True, root_path_in_servers: bool = True,
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
default_error_schema: Optional[DefaultErrorSchema] = None,
callbacks: Optional[List[BaseRoute]] = None, callbacks: Optional[List[BaseRoute]] = None,
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
include_in_schema: bool = True, include_in_schema: bool = True,
@ -123,6 +125,7 @@ class FastAPI(Starlette):
self.extra = extra self.extra = extra
self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {} self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
self.default_error_schema = default_error_schema
self.openapi_version = "3.0.2" self.openapi_version = "3.0.2"
if self.openapi_url: if self.openapi_url:
@ -141,6 +144,7 @@ class FastAPI(Starlette):
terms_of_service=self.terms_of_service, terms_of_service=self.terms_of_service,
contact=self.contact, contact=self.contact,
license_info=self.license_info, license_info=self.license_info,
default_error_schema=self.default_error_schema,
routes=self.routes, routes=self.routes,
tags=self.openapi_tags, tags=self.openapi_tags,
servers=self.servers, servers=self.servers,

4
fastapi/openapi/models.py

@ -151,6 +151,10 @@ class Example(BaseModel):
class Config: class Config:
extra = "allow" extra = "allow"
class DefaultErrorSchema(BaseModel):
status: int
description: Optional[str] = None
model: BaseModel
class ParameterInType(Enum): class ParameterInType(Enum):
query = "query" query = "query"

28
fastapi/openapi/utils.py

@ -29,6 +29,7 @@ from pydantic.schema import (
get_model_name_map, get_model_name_map,
) )
from pydantic.utils import lenient_issubclass from pydantic.utils import lenient_issubclass
from fastapi.openapi.models import DefaultErrorSchema
from starlette.responses import JSONResponse from starlette.responses import JSONResponse
from starlette.routing import BaseRoute from starlette.routing import BaseRoute
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
@ -167,7 +168,7 @@ def get_openapi_operation_metadata(
def get_openapi_path( def get_openapi_path(
*, route: routing.APIRoute, model_name_map: Dict[type, str] *, route: routing.APIRoute, model_name_map: Dict[type, str], default_error_schema: Optional[DefaultErrorSchema] = None
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]: ) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
path = {} path = {}
security_schemes: Dict[str, Any] = {} security_schemes: Dict[str, Any] = {}
@ -296,12 +297,30 @@ def get_openapi_path(
deep_dict_update(openapi_response, process_response) deep_dict_update(openapi_response, process_response)
openapi_response["description"] = description openapi_response["description"] = description
http422 = str(HTTP_422_UNPROCESSABLE_ENTITY) http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
if (all_route_params or route.body_field) and not any( if(default_error_schema is not None):
operation["responses"][default_error_schema["status"]] = {
"description": default_error_schema["description"],
"content": {
"application/json": {
"schema": {"$ref": REF_PREFIX + default_error_schema["name"] }
},
}
}
definitions.update(
{
default_error_schema["name"]: {
"title": default_error_schema["name"],
"type": "object",
"properties": default_error_schema["properties"]
}
}
)
elif (all_route_params or route.body_field) and not any(
[ [
status in operation["responses"] status in operation["responses"]
for status in [http422, "4XX", "default"] for status in [http422, "4XX", "default"]
] ]
): ):
operation["responses"][http422] = { operation["responses"][http422] = {
"description": "Validation Error", "description": "Validation Error",
"content": { "content": {
@ -362,6 +381,7 @@ def get_openapi(
openapi_version: str = "3.0.2", openapi_version: str = "3.0.2",
description: Optional[str] = None, description: Optional[str] = None,
routes: Sequence[BaseRoute], routes: Sequence[BaseRoute],
default_error_schema: Optional[DefaultErrorSchema] = None,
tags: Optional[List[Dict[str, Any]]] = None, tags: Optional[List[Dict[str, Any]]] = None,
servers: Optional[List[Dict[str, Union[str, Any]]]] = None, servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
terms_of_service: Optional[str] = None, terms_of_service: Optional[str] = None,
@ -389,7 +409,7 @@ def get_openapi(
) )
for route in routes: for route in routes:
if isinstance(route, routing.APIRoute): if isinstance(route, routing.APIRoute):
result = get_openapi_path(route=route, model_name_map=model_name_map) result = get_openapi_path(route=route, model_name_map=model_name_map, default_error_schema=default_error_schema)
if result: if result:
path, security_schemes, path_definitions = result path, security_schemes, path_definitions = result
if path: if path:

Loading…
Cancel
Save