System Proxy Plugin
The built-in proxy plugin has two core roles in FrameX, plus one more advanced extension point.
Core Role 1: Add Upstream Services To Your Own API Surface
If you already have an upstream FastAPI service or another FrameX service, the proxy plugin can pull that service into the current FrameX API surface.
That means callers can keep using the current FrameX service, while some capabilities are actually forwarded to another service behind the scenes.
Typical uses:
- keep an existing FastAPI service while introducing FrameX gradually
- aggregate multiple services behind one FrameX boundary
- expose upstream APIs through the same
/api/v1/...style surface as local plugins
Minimal Config
load_builtin_plugins = ["proxy"]
[server]
enable_proxy = true
[plugins.proxy]
white_list = ["/*"]
force_stream_apis = ["/api/v1/chat/stream"]
timeout = 600
[plugins.proxy.proxy_urls."http://127.0.0.1:9000"]
enable = ["/api/v1/*"]
disable = []
This proxy_urls mapping is the current full config form in the codebase.
The older list form still exists in the type definition, but if you want per-upstream control, use the dict form shown above.
How It Works
At startup, the proxy plugin reads the upstream /api/v1/openapi.json document, filters routes through the configured allow rules, and registers matching forwarding routes locally.
The current implementation supports:
- query parameters
- JSON request bodies
multipart/form-data- file uploads
- explicitly marked streaming APIs
Core Role 2: Preserve Privacy And Isolation In Multi-Plugin Collaboration
The second role is more important in larger systems.
In a multi-plugin or multi-team setup, one team may need to call another team's capability without having that plugin code locally.
In that case, the caller only depends on the API contract, not on the other team's implementation.
This gives you two benefits:
- implementation privacy: the upstream plugin code does not need to be shared locally
- codebase isolation: one team does not need to understand or import another team's plugin package
What This Looks Like
A plugin declares the API it depends on:
__plugin_meta__ = PluginMetadata(
name="invoker",
version=VERSION,
description="Calls another capability through a stable API",
author="you",
url="https://github.com/touale/FrameX-kit",
required_remote_apis=["/api/v1/base/version"],
)
Then it calls that API through the normal public interface:
from framex import call_plugin_api
version = await call_plugin_api("/api/v1/base/version")
If that API exists locally, FrameX uses the local plugin.
If it does not exist locally and proxy mode is enabled, the HTTP path can fall back to the proxy plugin and be forwarded to an upstream service.
That is the key point: the calling side does not need to change just because the real implementation lives somewhere else.
Proxy URL Rules
The proxy plugin supports two rule levels:
- global rules through
white_list - per-upstream rules through
proxy_urls.<base_url>.enableandproxy_urls.<base_url>.disable
Example:
[plugins.proxy]
white_list = ["/api/v1/*"]
[plugins.proxy.proxy_urls."http://127.0.0.1:9000"]
enable = ["/api/v1/*"]
disable = ["/api/v1/internal/*"]
Rule order in the code is:
- per-URL
disable - per-URL
enable - global
white_list
Streaming APIs
If an upstream route should stay on the streaming path, add it to force_stream_apis:
[plugins.proxy]
force_stream_apis = ["/api/v1/chat/stream"]
Those paths stay on the streaming code path instead of being handled as normal JSON responses.
Authentication
If the upstream service is another FrameX service and it has enabled auth.rules, you need to configure matching keys in plugins.proxy.auth.rules so the proxy plugin can call it successfully.
The proxy plugin uses these rules in two places:
- when fetching the upstream
/api/v1/openapi.json - when forwarding requests to protected upstream API paths
Example:
[plugins.proxy.auth]
rules = {
"/api/v1/openapi.json" = ["docs-key"],
"/api/v1/base/version" = ["service-key"],
"/api/v1/base/*" = ["service-key"]
}
That means:
- the proxy plugin uses
docs-keyto read the upstream OpenAPI document - it uses
service-keywhen forwarding protected API calls to/api/v1/base/versionor/api/v1/base/*
So if a cloud FrameX service protects its routes with auth.rules, the local service must mirror the needed upstream path rules in plugins.proxy.auth.rules and provide the corresponding keys.
For the full auth model and rule behavior on the upstream service itself, see Security & Authorization.
Advanced Use Cases
The proxy plugin also supports more advanced usage patterns beyond plain HTTP route forwarding.
One of them is function-style proxying and remote invocation. That topic is covered separately in Proxy Function & Remote Invocation.
Rule Of Thumb
Use the proxy plugin when you need one of these outcomes:
- expose an upstream FastAPI or FrameX service through your current FrameX API surface
- let one plugin call another team's capability without importing or shipping that plugin locally
- keep API names stable while the real implementation moves between local and remote services