Reverse proxy¶
Forward inbound requests to an upstream API over http.Client. This is the
outbound side: a named, pooled client (configured under clients.api) is reused
across requests, and a catch-all route forwards the remaining path to the
upstream and relays the response.
This mirrors
examples/proxy.py.
Script¶
from siphon import http, log
@http.route("/proxy/{*rest}", methods=["GET"])
async def forward(req):
path = "/" + req.path_params["rest"]
async with http.Client("api") as c:
upstream = await c.get(path)
log.info(f"proxied {path} -> {upstream.status}")
content_type = upstream.headers.get("content-type", "application/octet-stream")
return http.Response(
status=upstream.status,
headers={"Content-Type": content_type},
body=upstream.body,
)
Listener + client¶
The route needs an inbound listener and a named outbound client:
# http.yaml
servers:
- listen: "127.0.0.1:8080"
clients:
api:
base_url: "https://api.example.com"
timeout_ms: 5000
Try it¶
That forwards to https://api.example.com/v1/status and relays the upstream
status, content type, and body back to the caller.
How it works¶
- Catch-all route.
/proxy/{*rest}captures everything after/proxy/intoreq.path_params["rest"]. See Script API →@http.route. - Named, pooled client.
http.Client("api")resolves toclients.apiin the config and reuses a pooled connection;base_urlmeans the handler passes only the relative path. See Configuration → clients and Script API →http.Client. - Relaying the response. The upstream
Responseexposes.status,.headers, and.body, which the handler copies into its ownhttp.Response.
Response rewriting happens in the handler
Because middleware is a request guard today, any response rewriting — header stripping, body transforms — is done inline in the route handler, as above.