# Conflicts: # backend/main.py # backend/schemas.py # sidecar/sidecar.py # sidecar/test_claude_args.py
41 lines
1.6 KiB
Python
41 lines
1.6 KiB
Python
"""Route helpers: OpenAPI response-schema attachment and worker-thread JSON."""
|
||
|
||
import functools
|
||
|
||
from fastapi.responses import JSONResponse
|
||
|
||
|
||
def _r(model) -> dict:
|
||
"""Attach a response schema to a route for OpenAPI/codegen **only**.
|
||
|
||
Passed as ``responses=`` (not ``response_model=``) so FastAPI documents the
|
||
200 body in ``/openapi.json`` — which Orval turns into the frontend's types —
|
||
without validating or filtering the handler's actual return value. See
|
||
``schemas/``."""
|
||
return {200: {"model": model}}
|
||
|
||
|
||
def _json_in_worker(fn):
|
||
"""Serialize a heavy sync GET's body inside its worker thread.
|
||
|
||
A handler returning a plain dict is encoded by FastAPI's pure-Python
|
||
``jsonable_encoder`` **on the event loop**, after the threadpool hands the
|
||
value back — 5-10× slower than ``json.dumps`` (the full conversation list:
|
||
~430 ms vs ~70 ms), and while it runs nothing else is served, not even
|
||
``/api/health``. Returning a ready ``JSONResponse`` from the handler moves
|
||
that work onto the worker thread. A body ``json.dumps`` can't encode
|
||
(a set, a model, a NaN) falls back to FastAPI's encoder unchanged.
|
||
|
||
Only for plain ``@app.get`` handlers with the default 200 status and no
|
||
``Response`` parameter — a returned response replaces both."""
|
||
@functools.wraps(fn)
|
||
def wrapper(*args, **kwargs):
|
||
out = fn(*args, **kwargs)
|
||
if isinstance(out, (dict, list)):
|
||
try:
|
||
return JSONResponse(out)
|
||
except (TypeError, ValueError):
|
||
return out
|
||
return out
|
||
return wrapper
|