"The power of Rust. Modern DX. LLM-ready."
"API surface is ours, engines can change."
This single principle drives every architectural decision in RustAPI. You write code against a stable, ergonomic API. We handle the complexity of HTTP protocols, async runtimes, and serialization libraries internally.
Building APIs in Rust traditionally requires:
- Understanding
hyper's low-level HTTP primitives - Managing
tokioruntime configurations - Fighting trait bounds like
Pin<Box<dyn Future<...>>> - Writing boilerplate for request parsing, validation, and error handling
- Manually documenting every endpoint
The result? Simple APIs take 100+ lines. Developers spend more time on plumbing than business logic.
RustAPI provides a facade — a clean, stable API that wraps all the complexity:
// This is all you need. No boilerplate.
use rustapi_rs::prelude::*;
#[rustapi_rs::get("/users/{id}")]
async fn get_user(Path(id): Path<u64>) -> Json<User> {
Json(User::find(id).await)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
RustApi::auto().run("0.0.0.0:8080").await
}5 lines. Auto-generated OpenAPI. Production-ready.
Every feature must be expressible in minimal code.
| Framework | Hello World Lines |
|---|---|
| Raw Hyper | ~50 lines |
| Axum | ~15 lines |
| RustAPI | 5 lines |
We achieve this through:
- Sensible defaults (auto-route registration, built-in Swagger UI)
- Derive macros that eliminate boilerplate
- A prelude that exports everything you need
Your code depends only on rustapi-rs. Internal dependencies are hidden.
# Your Cargo.toml - simple and stable
[dependencies]
rustapi-rs = "0.1"You never write:
# ❌ Not this - internal details exposed
hyper = "1.0"
tokio = "1.35"
validator = "0.16"Benefits:
- No dependency conflicts
- Simpler
Cargo.toml - We can upgrade internals without breaking your code
The facade pattern lets us swap implementations freely.
| Component | Current Engine | Could Become |
|---|---|---|
| HTTP Server | hyper 1.x |
hyper 2.x, h3 (HTTP/3) |
| Async Runtime | tokio |
smol, async-std (future) |
| Validation | rustapi-validate |
Custom engine (available) |
| Router | matchit |
Custom radix tree |
| OpenAPI | utoipa |
Native implementation |
Example scenario: When hyper 2.0 releases with breaking changes:
- We update
rustapi-coreto usehyper 2.0 - We bump
rustapi-rsto0.2.0 - Your code stays exactly the same — just update the version
RustAPI already hides external crates behind internal adapters. To reduce dependency debt, we target components with stable specs and small surface areas for replacement, while keeping the public API unchanged. The playbook is:
- Wrap dependencies with internal traits/types so behavior is defined by RustAPI.
- Add contract tests to lock in behavior before replacing internals.
- Ship replacements behind feature flags, then flip defaults.
Good candidates for in-house implementations:
- Router (
matchit) → internal radix tree with RustAPI-specific optimizations. - OpenAPI (
utoipa) → native schema generator to control outputs. - TOON format (
toon-format) → move core format logic intorustapi-toon. - Template engine (
tera) → minimal renderer for basic HTML views.
Not near-term targets: tokio, hyper, tower — large, security-sensitive, and foundational crates best kept upstream for now.
Everything you need, nothing you don't.
# Just the basics
rustapi-rs = "0.1"
# Kitchen sink
rustapi-rs = { version = "0.1", features = ["full"] }
# Pick what you need
rustapi-rs = { version = "0.1", features = ["jwt", "cors", "toon"] }| Feature | What You Get |
|---|---|
jwt |
JWT authentication with AuthUser<T> extractor |
cors |
CORS middleware with builder pattern |
rate-limit |
IP-based rate limiting |
toon |
LLM-optimized TOON format |
swagger-ui |
Auto-generated /docs endpoint |
full |
All features enabled |
Built for the AI era.
Traditional JSON:
{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}],"total":2}→ ~20 tokens
TOON format:
users[(id:1,name:Alice)(id:2,name:Bob)]total:2
→ ~9 tokens (55% savings)
RustAPI provides:
Toon<T>— Direct TOON responsesLlmResponse<T>— Content negotiation with token counting headersAcceptHeader— Automatic format detection
#[rustapi_rs::get("/ai/data")]
async fn ai_endpoint(accept: AcceptHeader) -> LlmResponse<Data> {
LlmResponse::new(data, accept.preferred)
}
// Response headers: X-Token-Count-JSON, X-Token-Count-TOON, X-Token-Savings// ❌ We don't expose hyper types
fn handler(req: hyper::Request<...>) -> hyper::Response<...>
// ✅ We provide our own abstractions
fn handler(req: Request) -> impl IntoResponse// ❌ Not this
let server = Server::builder()
.http1_header_max_size(8192)
.http1_only(true)
.tcp_keepalive(Some(Duration::from_secs(60)))
.build(...);
// ✅ This
RustApi::new().run("0.0.0.0:8080").await// ❌ Not this
where
T: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
T::Error: Into<BoxError>,
T::Future: Send,
ResBody: Body<Data = Bytes> + Send + 'static,
ResBody::Error: Into<BoxError>,
// ✅ Just this
async fn handler(Json(body): Json<T>) -> Json<R>| Goal | Target | Achieved |
|---|---|---|
| Hello World | ≤ 5 lines | ✅ 5 lines |
| CRUD tutorial | ≤ 15 min | ✅ ~10 min |
| First Swagger UI | Zero config | ✅ Auto at /docs |
| Compile errors | Understandable | ✅ Clear hints |
| LLM token savings | ≥ 50% | ✅ 50-58% |
- Polish existing features
- Performance optimizations (simd-json, better allocations)
- More middleware (compression, static files)
- Custom validation engine (remove
validatordependency) - Async validation support
- Stable API guarantee
- WebSocket support
- GraphQL (optional crate)
- gRPC (optional crate)
- HTTP/3 via
h3(transparent upgrade)
RustAPI is not just another web framework. It's a philosophy:
- Simplicity first — 5 lines to production
- Stability always — Your code never breaks
- Future-ready — Built for AI, ready for anything
use rustapi_rs::prelude::*;
// This will work in 2024, 2025, and beyond.
// Engines change. Your code doesn't."API surface is ours, engines can change."