https://github.com/structured-world/structured-proxy
Universal gRPC→REST transcoding proxy — config-driven, works with any gRPC service
https://github.com/structured-world/structured-proxy
Last synced: 14 days ago
JSON representation
Universal gRPC→REST transcoding proxy — config-driven, works with any gRPC service
- Host: GitHub
- URL: https://github.com/structured-world/structured-proxy
- Owner: structured-world
- License: apache-2.0
- Created: 2026-03-14T15:01:57.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-03-25T18:34:19.000Z (3 months ago)
- Last Synced: 2026-03-26T19:16:20.116Z (3 months ago)
- Language: Rust
- Size: 65.4 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# structured-proxy
Universal, config-driven gRPC→REST transcoding proxy. One binary, different YAML configs — different products.
Works with **any** gRPC service via proto descriptor files. No code generation, no custom handlers — just configuration.
## Features
- **Dynamic REST routes** from proto descriptors using `google.api.http` annotations
- **Auto-generated OpenAPI** documentation from proto messages
- **Server-streaming** RPC → SSE/chunked HTTP responses
- **Rate limiting (Shield)** — endpoint classification + per-identifier limiting via YAML
- **JWT/OIDC validation** — route-level auth policies with JWKS auto-discovery
- **Path aliasing** — configurable route remapping (e.g., `/oauth2/*` → `/v1/oauth2/*`)
- **Maintenance mode** — 503 with configurable exempt paths
- **Health endpoints** — `/health/live`, `/health/ready`, `/health/startup`
- **Prometheus metrics** — `/metrics` endpoint
- **Zero code changes** between services — same binary, different config
## Quick Start
```bash
# Install
cargo install structured-proxy
# Run with your service config
structured-proxy --config my-service.yaml
```
## Configuration
```yaml
# my-service.yaml
listen: "0.0.0.0:8080"
upstream:
address: "http://127.0.0.1:50051"
descriptor:
file: "my-service.descriptor.bin"
# OR: reflection: true
cors:
allow_origins: ["*"]
# Optional: path aliases
aliases:
- from: "/api/v1/*"
to: "/my.package.v1.MyService/*"
# Optional: rate limiting
shield:
enabled: true
default_rpm: 60
endpoints:
- pattern: "/api/v1/heavy-*"
rpm: 10
identifier: header:x-api-key
```
Generate the descriptor file from your proto:
```bash
buf build -o my-service.descriptor.bin
# or
protoc --descriptor_set_out=my-service.descriptor.bin --include_imports *.proto
```
## Library Usage
```rust
use structured_proxy::{ProxyConfig, build_proxy};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = ProxyConfig::from_file("my-service.yaml")?;
let app = build_proxy(config).await?;
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await?;
Ok(())
}
```
## How It Works
1. Load proto descriptor (file or gRPC reflection)
2. Parse `google.api.http` annotations → generate REST routes
3. Incoming HTTP request → transcode to gRPC (path params, query params, JSON body → protobuf)
4. Forward to upstream gRPC service
5. Response protobuf → transcode to JSON
6. Serve OpenAPI spec at `/openapi.json`
## Architecture
```
Client (HTTP/JSON)
│
▼
┌─────────────────────┐
│ structured-proxy │
│ │
│ ┌────────────────┐ │
│ │ Shield (rate) │ │
│ ├────────────────┤ │
│ │ Auth (JWT) │ │
│ ├────────────────┤ │
│ │ Transcoder │ │ REST → gRPC
│ │ (prost-reflect)│ │ JSON → Protobuf
│ ├────────────────┤ │
│ │ OpenAPI gen │ │ /openapi.json
│ └────────────────┘ │
└─────────┬────────────┘
│ gRPC
▼
Upstream Service
```
## License
Apache-2.0