tune openapi

This commit is contained in:
L-Nafaryus 2024-08-30 23:28:58 +05:00
parent 1b1142a0b0
commit adc4a59932
Signed by: L-Nafaryus
GPG Key ID: 553C97999B363D38
5 changed files with 65 additions and 24 deletions

View File

@ -5,6 +5,7 @@ from typing import AsyncIterator, TypedDict, Self, Optional
import uvicorn import uvicorn
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.routing import APIRoute
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from materia.core import ( from materia.core import (
Config, Config,
@ -15,6 +16,7 @@ from materia.core import (
Cron, Cron,
) )
from materia import routers from materia import routers
from materia.core.misc import optional, optional_string
class Context(TypedDict): class Context(TypedDict):
@ -57,7 +59,7 @@ class Application:
await app.prepare_database() await app.prepare_database()
await app.prepare_cache() await app.prepare_cache()
await app.prepare_cron() await app.prepare_cron()
await app.prepare_server() app.prepare_server()
except Exception as e: except Exception as e:
app.logger.error(" ".join(e.args)) app.logger.error(" ".join(e.args))
sys.exit() sys.exit()
@ -99,7 +101,7 @@ class Application:
self.config.cron.workers_count, backend_url=url, broker_url=url self.config.cron.workers_count, backend_url=url, broker_url=url
) )
async def prepare_server(self): def prepare_server(self):
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[Context]: async def lifespan(app: FastAPI) -> AsyncIterator[Context]:
yield Context( yield Context(
@ -129,6 +131,13 @@ class Application:
self.backend.include_router(routers.resources.router) self.backend.include_router(routers.resources.router)
self.backend.include_router(routers.root.router) self.backend.include_router(routers.root.router)
for route in self.backend.routes:
if isinstance(route, APIRoute):
route.operation_id = (
optional_string(optional(route.tags.__getitem__, 0), "{}_")
+ route.name
)
async def start(self): async def start(self):
self.logger.info(f"Spinning up cron workers [{self.config.cron.workers_count}]") self.logger.info(f"Spinning up cron workers [{self.config.cron.workers_count}]")
self.cron.run_workers() self.cron.run_workers()

View File

@ -5,6 +5,7 @@ from materia.core.config import Config
from materia.core.logging import Logger from materia.core.logging import Logger
from materia.app import Application from materia.app import Application
import asyncio import asyncio
import json
@click.group() @click.group()
@ -112,5 +113,36 @@ def config_check(path: Path):
logger.info("OK.") logger.info("OK.")
@cli.group()
def export():
pass
@export.command("openapi", help="Export an OpenAPI specification.")
@click.option(
"--path",
"-p",
type=Path,
default=Path.cwd().joinpath("openapi.json"),
help="Path to the file.",
)
def export_openapi(path: Path):
path = path.resolve()
logger = Logger.new()
config = Config()
app = Application(config)
app.prepare_server()
logger.info("Writing file at {}", path)
try:
with open(path, "w") as io:
json.dump(app.backend.openapi(), io, sort_keys=False)
except Exception as e:
logger.error("{}", e)
logger.info("All done.")
if __name__ == "__main__": if __name__ == "__main__":
cli() cli()

View File

@ -34,10 +34,14 @@ class Cron:
): ):
cron = Cron( cron = Cron(
workers_count, workers_count,
# TODO: change log level
# TODO: exclude pickle
# TODO: disable startup banner
Celery( Celery(
"cron", "cron",
backend=backend_url, backend=backend_url,
broker=broker_url, broker=broker_url,
broker_connection_retry_on_startup=True,
task_serializer="pickle", task_serializer="pickle",
accept_content=["pickle", "json"], accept_content=["pickle", "json"],
**kwargs, **kwargs,

View File

@ -68,7 +68,23 @@ class FileSizeValidator:
raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE) raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE)
@router.post("/file") @router.post("/file", openapi_extra={
"requestBody" : {
"content": {
"multipart/form-data": {
"schema": {
"required": ["file", "path"],
"type": "object",
"properties": {
"file": { "type": "string", "format": "binary" },
"path": { "type": "string", "format": "path", "example": "/"}
}
}
}
},
"required": True
}
})
async def create( async def create(
request: Request, request: Request,
repository: Repository = Depends(middleware.repository), repository: Repository = Depends(middleware.repository),

View File

@ -129,27 +129,7 @@ async def api_client(
app.database = database app.database = database
app.cache = cache app.cache = cache
app.cron = cron app.cron = cron
await app.prepare_server() app.prepare_server()
# logger = make_logger(api_config)
# @asynccontextmanager
# async def lifespan(app: FastAPI) -> AsyncIterator[AppContext]:
# yield AppContext(
# config=api_config, database=database, cache=cache, logger=logger
# )
# app = FastAPI(lifespan=lifespan)
# app.include_router(routers.api.router)
# app.include_router(routers.resources.router)
# app.include_router(routers.root.router)
# app.add_middleware(
# CORSMiddleware,
# allow_origins=["*"],
# allow_credentials=True,
# allow_methods=["*"],
# allow_headers=["*"],
# )
async with LifespanManager(app.backend) as manager: async with LifespanManager(app.backend) as manager:
async with AsyncClient( async with AsyncClient(