ApiGate
ApiGate is a macro-driven API gateway for Rust services.
It lets you declare reverse-proxy routes as Rust modules, validate typed request data, run pre-proxy hooks, transform requests before forwarding, choose upstream backends with routing/balancing policies, and customize errors and observability without exposing axum details in your application code.
Under the hood ApiGate is built on axum, hyper-util, tower, and tracing.
Contents
- What It Provides
- Benchmarks
- Installation
- Supported Rust
- Quick Start
- Core Concepts
- API Reference
- Performance Notes
- Examples
What It Provides
- Declarative service and route macros:
#[apigate::service],#[apigate::get],#[apigate::post], etc. - Reverse proxying with streaming passthrough when a route does not need to read the body.
- Typed validation for
path,query,json, andforminputs. beforehooks for auth, headers, request metadata, and per-request state.mapfunctions for typed request transformation before the upstream call.- Multipart passthrough without buffering file bodies.
- Built-in policies: round-robin, consistent hash, header/path sticky, least-request, least-time.
- Custom routing strategies and custom balancers.
- Custom error rendering, including JSON envelopes and fully custom hook/map responses.
- Optional runtime observability through
tracingor a custom runtime observer. - External
tower/axummiddleware composition through the underlying router.
Benchmarks
ApiGate is benchmarked against Kong, Apache APISIX, and a tuned Python ASGI gateway in a reproducible load-test repo: OlegDokuchaev/apigate-benchmark.
The latest run uses the same Go auth/data backends for every gateway and runs one gateway at a time on a 4 vCPU / 10 GiB Linux host.
| Profile | Result |
|---|---|
| Steady, 2500 RPS | ApiGate p99 latency is 33-144% faster than APISIX, 52-391% faster than Kong, and 317-3857% faster than Python depending on route. |
| Ramp, 0 -> 20000 RPS | ApiGate delivers 6-31% more average RPS than APISIX, 1-41% more than Kong, and 115-184% more than Python before the p99 abort threshold. |
| Stress, 9000 RPS | ApiGate p99 latency is 7-70% faster than APISIX, 32-159% faster than Kong, and much faster than Python on saturated routes. |
See Performance Notes for steady-state latency numbers and links to the full benchmark results.
Installation
Add the facade crate to your application:
[]
= "1.0.0"
= { = "1", = ["rt-multi-thread", "macros"] }
= { = "1", = ["derive"] }
= "1"
Optional dependencies used in examples:
= "0.8"
= "1"
= "1"
= "0.1"
= { = "0.3", = ["env-filter", "fmt"] }
= { = "0.6", = ["trace"] }
= { = "1", = ["v4", "serde"] }
Supported Rust
ApiGate declares Rust 1.88 as its package rust-version. Rust 1.88 stabilizes let chains in the Rust 2024 edition, which ApiGate uses in its implementation. CI checks that the library crates compile on Rust 1.88 and runs the full test suite on the latest stable toolchain.
Quick Start
use SocketAddr;
async
Run a local upstream and the example gateway:
Then call:
Core Concepts
ApiGate has three layers:
| Layer | Purpose |
|---|---|
| Service | A macro-generated collection of routes with an optional prefix and default policy. |
| Route | An HTTP method/path declaration with optional validation, hooks, mapping, rewrite, and policy override. |
| App | Runtime configuration: mounted services, upstream backends, shared state, timeouts, policies, errors, and observability. |
The normal flow is:
- A request matches an axum route generated by ApiGate.
- ApiGate optionally extracts typed path parameters.
beforehooks run in order.- The route optionally validates or maps
query,json, orformdata. - A routing strategy selects candidate backends.
- A balancer picks one backend.
- ApiGate rewrites the URI and proxies the request to the upstream.
- Runtime events are emitted only if a runtime observer is configured.
API Reference
The detailed API guide lives in docs/reference.md. It keeps the README focused on installation, the first gateway, core concepts, and performance.
Reference sections:
| Topic | Link |
|---|---|
| Services and route declarations | Services, Routes |
| Typed inputs and rewrites | Typed Inputs, Path Rewrites |
| Hooks and maps | Hooks, Maps, Hook and Map Parameters |
| Shared and per-request state | Shared and Per-Request State |
| Errors | Error Handling |
| Observability and tower layers | Runtime Observability and Tracing, External Tower Layers |
| Policies and balancing | Policies, Routing, and Balancing |
| Runtime tuning and serving helpers | App Builder Reference |
Performance Notes
ApiGate is designed to avoid unnecessary work on routes that do not need it:
- Routes without
path,before,query,json,form, ormaphave no generated pipeline and proxy the body as streaming passthrough. - Multipart routes stream the request body without reading or buffering it.
jsonandformvalidation read the body only when the route declares typed validation or mapping.queryvalidation does not read the body.- Shared app state is accessed by reference through
Extensions; read-only&Taccess does not clone per request. - Per-request
RequestScopelocal storage allocates only when values are inserted. - Route metadata is stored in a table and request routing carries a small route index.
- The upstream client uses keep-alive pooling,
TCP_NODELAY, configurable connect timeout, configurable idle timeout, and exposes hyper-util client/connector tuning hooks. - Built-in balancers are lock-free and use atomics.
- Runtime observer is disabled by default; when disabled, the hot path only performs an
Optioncheck.
Routes with json, form, or mapped bodies intentionally allocate for parsed/serialized payloads. Keep those routes for boundaries where validation or transformation is worth the cost.
Benchmark Results
The benchmark suite compares ApiGate with Kong, Apache APISIX, and a tuned Python ASGI gateway over the same Go auth/data backends. The latest run used a 4 vCPU / 10 GiB Linux host and tested plain proxying, auth hook + header injection, JSON validation, and typed request mapping/rewrite.
Steady-state p99 latency at 2500 RPS:
| Route | ApiGate | APISIX | Kong | Python |
|---|---|---|---|---|
GET /items |
1.76 ms | 2.40 ms | 2.84 ms | 7.33 ms |
GET /my-items |
3.34 ms | 8.15 ms | 16.38 ms | 132.1 ms |
POST /items/search |
1.91 ms | 2.53 ms | 2.94 ms | 20.52 ms |
POST /items/lookup |
1.86 ms | 2.75 ms | 2.83 ms | 22.05 ms |
For comparative throughput and latency numbers, see the reproducible ApiGate benchmark suite and its latest results.
Examples
Run the mock upstream first:
Then run any example:
Example guide:
| Example | Shows |
|---|---|
basic |
Passthrough proxying, static rewrite, rewrite templates. |
hooks |
Shared state, auth, header injection, hook chains, per-request scope data. |
errors |
Global JSON error renderer, user/debug message separation, custom JSON from hooks. |
logging |
Built-in tracing observer and custom runtime observer. |
tower_logging |
External tower_http::TraceLayer with .with_router(...). |
runtime_tuning |
Listener socket tuning plus upstream hyper-util client/connector settings. |
path |
Typed path validation, path data in hooks, path data in maps. |
map |
Query, JSON, and form transformations. |
policy |
Header/path sticky routing, consistent hash, least-request, least-time, round-robin. |
multipart |
Multipart upload passthrough with and without auth. |
Each example prints ready-to-run curl commands.