86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
from aiohttp.web import json_response, Response
|
|
|
|
from aiohttp_pydantic.oas.struct import OpenApiSpec3, OperationObject, PathItem
|
|
from typing import Type
|
|
|
|
from ..injectors import _parse_func_signature
|
|
from ..view import PydanticView, is_pydantic_view
|
|
|
|
|
|
JSON_SCHEMA_TYPES = {float: "number", str: "string", int: "integer"}
|
|
|
|
|
|
def _add_http_method_to_oas(oas_path: PathItem, method: str, view: Type[PydanticView]):
|
|
method = method.lower()
|
|
mtd: OperationObject = getattr(oas_path, method)
|
|
handler = getattr(view, method)
|
|
path_args, body_args, qs_args, header_args = _parse_func_signature(handler)
|
|
|
|
if body_args:
|
|
mtd.request_body.content = {
|
|
"application/json": {"schema": next(iter(body_args.values())).schema()}
|
|
}
|
|
|
|
i = 0
|
|
for i, (name, type_) in enumerate(path_args.items()):
|
|
mtd.parameters[i].required = True
|
|
mtd.parameters[i].in_ = "path"
|
|
mtd.parameters[i].name = name
|
|
mtd.parameters[i].schema = {"type": JSON_SCHEMA_TYPES[type_]}
|
|
|
|
for i, (name, type_) in enumerate(qs_args.items(), i + 1):
|
|
mtd.parameters[i].required = False
|
|
mtd.parameters[i].in_ = "query"
|
|
mtd.parameters[i].name = name
|
|
mtd.parameters[i].schema = {"type": JSON_SCHEMA_TYPES[type_]}
|
|
|
|
for i, (name, type_) in enumerate(header_args.items(), i + 1):
|
|
mtd.parameters[i].required = False
|
|
mtd.parameters[i].in_ = "header"
|
|
mtd.parameters[i].name = name
|
|
mtd.parameters[i].schema = {"type": JSON_SCHEMA_TYPES[type_]}
|
|
|
|
|
|
async def get_oas(request):
|
|
"""
|
|
Generate Open Api Specification from PydanticView in application.
|
|
"""
|
|
apps = request.app["apps to expose"]
|
|
oas = OpenApiSpec3()
|
|
for app in apps:
|
|
for resources in app.router.resources():
|
|
for resource_route in resources:
|
|
if is_pydantic_view(resource_route.handler):
|
|
view: Type[PydanticView] = resource_route.handler
|
|
info = resource_route.get_info()
|
|
path = oas.paths[info.get("path", info.get("formatter"))]
|
|
if resource_route.method == "*":
|
|
for method_name in view.allowed_methods:
|
|
_add_http_method_to_oas(path, method_name, view)
|
|
else:
|
|
_add_http_method_to_oas(path, resource_route.method, view)
|
|
|
|
return json_response(oas.spec)
|
|
|
|
|
|
async def oas_ui(request):
|
|
"""
|
|
View to serve the swagger-ui to read open api specification of application.
|
|
"""
|
|
template = request.app["index template"]
|
|
|
|
static_url = request.app.router["static"].url_for(filename="")
|
|
spec_url = request.app.router["spec"].url_for()
|
|
host = request.url.origin()
|
|
|
|
return Response(
|
|
text=template.render(
|
|
{
|
|
"openapi_spec_url": host.with_path(str(spec_url)),
|
|
"static_url": host.with_path(str(static_url)),
|
|
}
|
|
),
|
|
content_type="text/html",
|
|
charset="utf-8",
|
|
)
|