reflex/reflex/proxy.py
Masen Furer 7512afa949
Proxy backend requests on '/' to the frontend
If the optional extra `proxy` is installed, then the backend can handle all
requests by proxy unrecognized routes to the frontend nextjs server.
2024-05-13 21:29:45 -07:00

76 lines
2.3 KiB
Python

"""Handle proxying frontend requests from the backend server."""
from __future__ import annotations
from contextlib import asynccontextmanager
from typing import AsyncGenerator
from urllib.parse import urlparse
from fastapi import FastAPI
from starlette.types import ASGIApp
from .config import get_config
from .utils import console
try:
from asgiproxy.config import BaseURLProxyConfigMixin, ProxyConfig
from asgiproxy.context import ProxyContext
from asgiproxy.simple_proxy import make_simple_proxy_app
except ImportError:
@asynccontextmanager
async def proxy_middleware(*args, **kwargs) -> AsyncGenerator[None, None]:
"""A no-op proxy middleware for when asgiproxy is not installed.
Args:
*args: The positional arguments.
**kwargs: The keyword arguments.
Yields:
None
"""
yield
else:
def _get_proxy_app_with_context(frontend_host: str) -> tuple[ProxyContext, ASGIApp]:
"""Get the proxy app with the given frontend host.
Args:
frontend_host: The frontend host to proxy requests to.
Returns:
The proxy context and app.
"""
class LocalProxyConfig(BaseURLProxyConfigMixin, ProxyConfig):
upstream_base_url = frontend_host
rewrite_host_header = urlparse(upstream_base_url).netloc
proxy_context = ProxyContext(LocalProxyConfig())
proxy_app = make_simple_proxy_app(proxy_context)
return proxy_context, proxy_app
@asynccontextmanager
async def proxy_middleware( # pyright: ignore[reportGeneralTypeIssues]
api: FastAPI,
) -> AsyncGenerator[None, None]:
"""A middleware to proxy requests to the separate frontend server.
The proxy is installed on the / endpoint of the FastAPI instance.
Args:
api: The FastAPI instance.
Yields:
None
"""
config = get_config()
backend_port = config.backend_port
frontend_host = f"http://localhost:{config.frontend_port}"
proxy_context, proxy_app = _get_proxy_app_with_context(frontend_host)
api.mount("/", proxy_app)
console.debug(
f"Proxying '/' requests on port {backend_port} to {frontend_host}"
)
async with proxy_context:
yield