A robust, streaming-capable reverse proxy for FastAPI including WebSocket support.
Project description
FastAPI Reverse Proxy
A robust, streaming-capable reverse proxy for FastAPI/Starlette with built-in Latency-Based Load Balancing and Active Health Monitoring.
Features
- Streaming Ready: Efficiently handles SSE (Server-Sent Events) and large file uploads/downloads.
- WebSocket Support: Seamless bidirectional tunneling with automated subprotocol negotiation.
- Unified Load Balancing: Standard Round-Robin or Smart routing using a single utility.
- Latency-Based Routing: Automatically routes traffic to the fastest healthy server (HEAD probe).
- Advanced Overrides: Granular control over headers, body, and HTTP methods.
- Robust Cancellation: Specialized handling for
asyncio.CancelledErrorto prevent resource leaks. - Version Agnostic: Automatically handles
websocketslibrary version differences (12.0+ vs Legacy).
Quick Start (Best Practice)
The recommended way to use the library is within a FastAPI lifespan handler. This ensures all background monitoring tasks and HTTP clients start and stop cleanly.
from fastapi import FastAPI, Request, WebSocket
from contextlib import asynccontextmanager
from fastapi_reverse_proxy import (
HealthChecker, LoadBalancer,
create_httpx_client, close_httpx_client
)
# 1. Setup health monitoring and load balancing
checker = HealthChecker(["http://localhost:8080", "http://localhost:8081"])
lb = LoadBalancer(checker)
@asynccontextmanager
async def lifespan(app: FastAPI):
# Initialize global resources
await create_httpx_client(app)
async with checker: # Starts background health loop
yield
await close_httpx_client(app)
app = FastAPI(lifespan=lifespan)
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def gateway(request: Request, path: str):
# Route to the fastest healthy backend
return await lb.proxy_pass(request, path=f"/{path}")
@app.websocket("/ws/{path:path}")
async def ws_tunnel(websocket: WebSocket, path: str):
# Automatic subprotocol negotiation + Tunneling
await lb.proxy_pass_websocket(websocket, path=f"/{path}")
Advanced Proxying
The proxy_pass function and LoadBalancer.proxy_pass provide deep customization for upstream requests:
| Parameter | Type | Description |
|---|---|---|
method |
str |
Force a specific HTTP method (e.g., "POST"). |
override_body |
bytes |
Send custom data instead of the incoming request body. |
additional_headers |
dict |
Append custom headers to the proxied request. |
override_headers |
dict |
Use these headers instead of original request headers. |
forward_query |
bool |
Whether to append the incoming query string (Default: True). |
Monitoring & Configuration
HealthChecker (The Loop Owner)
The proactive component. It owns an internal asyncio background task that monitors backends.
- Immediate Start: When you enter the
async withblock (or callstart()), the checker performs an immediate check of all backends. This eliminates the "cold-start" window where backends are unknown. - Configuration Modes:
- Standard:
HealthChecker(["http://a", "http://b"], ping_path="/health") - Personalized: Pass a list of dictionaries for per-host settings:
checker = HealthChecker([ {"host": "http://api-1", "pingpath": "/v1/status", "maxrequests": 100}, {"host": "http://api-2", "pingpath": "/health"} ])
- Standard:
- Properties:
ping_path: Get or set the global health check path (default:"/").
LoadBalancer (The Decision Utility)
A normal Python object that makes routing decisions based on its source.
- Stateful: While it has no background loop, it does track state (request counts for rate-limiting and the last time it pulled data from the health checker).
- No Lifecycle Needed: It relies on the
HealthChecker(or a static list) for data and doesn't need explicitstart/stopcalls.
WebSocket Refinements
The library implements "deferred negotiation" for WebSockets:
- The proxy receives the client's supported subprotocols from
scope. - It establishes an upstream connection first.
- Once the upstream accepts a protocol, the proxy calls
websocket.accept(subprotocol=...)back to the client. - This ensures the entire tunnel (Client <-> Proxy <-> Upstream) uses the same negotiated protocol.
Robustness & Safety
- Termination Safety: Resource cleanup (closing
httpxclients and sockets) is triggered even on task cancellation (BaseException). - Introspection-Based Compatibility: Uses
inspect.signatureto automatically detect version-specific parameters in thewebsocketslibrary.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_reverse_proxy-0.1.1.tar.gz.
File metadata
- Download URL: fastapi_reverse_proxy-0.1.1.tar.gz
- Upload date:
- Size: 12.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ceb338696da6590ec325e7d141298e955591ec390fd9bf05dfb53e7668e41cd2
|
|
| MD5 |
00bad6c93fb82b4a46831d1369b81ba9
|
|
| BLAKE2b-256 |
292598b5f10915f83906dcd73d2dae215ac7ef3e18b47be7f627c93fcc501c44
|
Provenance
The following attestation bundles were made for fastapi_reverse_proxy-0.1.1.tar.gz:
Publisher:
python-publish.yml on tfsantos05/fastapi-reverse-proxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_reverse_proxy-0.1.1.tar.gz -
Subject digest:
ceb338696da6590ec325e7d141298e955591ec390fd9bf05dfb53e7668e41cd2 - Sigstore transparency entry: 983802867
- Sigstore integration time:
-
Permalink:
tfsantos05/fastapi-reverse-proxy@e562ef29ce9038127792bb9058e0a5654323ed9d -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/tfsantos05
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@e562ef29ce9038127792bb9058e0a5654323ed9d -
Trigger Event:
release
-
Statement type:
File details
Details for the file fastapi_reverse_proxy-0.1.1-py3-none-any.whl.
File metadata
- Download URL: fastapi_reverse_proxy-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
612c8eeb721e78f80a74a2ca3c0742f3985ff94b9bae6608f6ef817e08e25f98
|
|
| MD5 |
000b6e1da83edaa8f7eabeb7007f1c28
|
|
| BLAKE2b-256 |
ab612d07d063abd15c3626e1fd2c2415726a5535e3f60a5702b73e63cc81ea38
|
Provenance
The following attestation bundles were made for fastapi_reverse_proxy-0.1.1-py3-none-any.whl:
Publisher:
python-publish.yml on tfsantos05/fastapi-reverse-proxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_reverse_proxy-0.1.1-py3-none-any.whl -
Subject digest:
612c8eeb721e78f80a74a2ca3c0742f3985ff94b9bae6608f6ef817e08e25f98 - Sigstore transparency entry: 983802871
- Sigstore integration time:
-
Permalink:
tfsantos05/fastapi-reverse-proxy@e562ef29ce9038127792bb9058e0a5654323ed9d -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/tfsantos05
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@e562ef29ce9038127792bb9058e0a5654323ed9d -
Trigger Event:
release
-
Statement type: