Spaces:
Runtime error
Runtime error
"""Collection of utilities for FastAPI apps.""" | |
import inspect | |
from typing import Any, Type | |
from fastapi import FastAPI, Form | |
from pydantic import BaseModel | |
def as_form(cls: Type[BaseModel]) -> Any: | |
"""Adds an as_form class method to decorated models. | |
The as_form class method can be used with FastAPI endpoints | |
""" | |
new_params = [ | |
inspect.Parameter( | |
field.alias, | |
inspect.Parameter.POSITIONAL_ONLY, | |
default=(Form(field.default) if not field.required else Form(...)), | |
) | |
for field in cls.__fields__.values() | |
] | |
async def _as_form(**data): # type: ignore | |
return cls(**data) | |
sig = inspect.signature(_as_form) | |
sig = sig.replace(parameters=new_params) | |
_as_form.__signature__ = sig # type: ignore | |
setattr(cls, "as_form", _as_form) | |
return cls | |
def patch_fastapi(app: FastAPI) -> None: | |
"""Patch function to allow relative url resolution. | |
This patch is required to make fastapi fully functional with a relative url path. | |
This code snippet can be copy-pasted to any Fastapi application. | |
""" | |
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html | |
from starlette.requests import Request | |
from starlette.responses import HTMLResponse | |
async def redoc_ui_html(req: Request) -> HTMLResponse: | |
assert app.openapi_url is not None | |
redoc_ui = get_redoc_html( | |
openapi_url="./" + app.openapi_url.lstrip("/"), | |
title=app.title + " - Redoc UI", | |
) | |
return HTMLResponse(redoc_ui.body.decode("utf-8")) | |
async def swagger_ui_html(req: Request) -> HTMLResponse: | |
assert app.openapi_url is not None | |
swagger_ui = get_swagger_ui_html( | |
openapi_url="./" + app.openapi_url.lstrip("/"), | |
title=app.title + " - Swagger UI", | |
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, | |
) | |
# insert request interceptor to have all request run on relativ path | |
request_interceptor = ( | |
"requestInterceptor: (e) => {" | |
"\n\t\t\tvar url = window.location.origin + window.location.pathname" | |
'\n\t\t\turl = url.substring( 0, url.lastIndexOf( "/" ) + 1);' | |
"\n\t\t\turl = e.url.replace(/http(s)?:\/\/[^/]*\//i, url);" # noqa: W605 | |
"\n\t\t\te.contextUrl = url" | |
"\n\t\t\te.url = url" | |
"\n\t\t\treturn e;}" | |
) | |
return HTMLResponse( | |
swagger_ui.body.decode("utf-8").replace( | |
"dom_id: '#swagger-ui',", | |
"dom_id: '#swagger-ui',\n\t\t" + request_interceptor + ",", | |
) | |
) | |
# remove old docs route and add our patched route | |
routes_new = [] | |
for app_route in app.routes: | |
if app_route.path == "/docs": # type: ignore | |
continue | |
if app_route.path == "/redoc": # type: ignore | |
continue | |
routes_new.append(app_route) | |
app.router.routes = routes_new | |
assert app.docs_url is not None | |
app.add_route(app.docs_url, swagger_ui_html, include_in_schema=False) | |
assert app.redoc_url is not None | |
app.add_route(app.redoc_url, redoc_ui_html, include_in_schema=False) | |
# Make graphql realtive | |
from starlette import graphql | |
graphql.GRAPHIQL = graphql.GRAPHIQL.replace( | |
"({{REQUEST_PATH}}", '("." + {{REQUEST_PATH}}' | |
) | |