What Is Astrea?
Astrea turns your file structure into API routes — at compile time, with zero runtime cost. Drop a .rs file into the src/routes/ folder, and it becomes an HTTP endpoint. No manual route registration, no build.rs, no boilerplate.
Every handler looks the same:
async
That's it. No complex extractor signatures. No learning curve for each parameter type.
Features
- 📁 File-based routing — file name = route path, generated at compile time
- 🎯 Unified handler signature — every handler is
async fn(Event) -> Result<Response> - 🔧 Simple extractors —
get_param(),get_query_param(),get_body()— just call a function - 🧅 Scoped middleware —
_middleware.rsfiles with inherit (extend) or replace (override) modes - 📝 OpenAPI auto-gen — optional Swagger UI + OpenAPI 3.0 spec from your code (feature flag
openapi) - 🔄 Axum compatible — works with all existing Axum middleware and the Tower ecosystem
- 📦 Zero extra deps — re-exports
axum,tokio,serde,tower, etc. — just depend onastrea
Quick Start
1. Create a new project
2. Add Astrea
Or in Cargo.toml:
[]
= "my-api"
= "2024"
[]
= "0.0.1"
Note: Astrea requires Rust edition 2024 (Rust ≥ 1.85).
3. Create your route files
my-api/
├── src/
│ ├── main.rs
│ └── routes/
│ ├── index.get.rs # GET /
│ └── users/
│ ├── index.get.rs # GET /users
│ ├── index.post.rs # POST /users
│ └── [id].get.rs # GET /users/:id
src/routes/index.get.rs
use *;
pub async
src/routes/users/[id].get.rs
use *;
pub async
4. Write main.rs
async
5. Run
Done. You will see a beautiful startup log:
┌─────────────────────────────────────────────────────────────────────┐
│ 🚀 Astrea Router │
├────────┬──────────────────────────────┬─────────────────────────────┤
│ Method │ Path │ Middleware │
├────────┼──────────────────────────────┼─────────────────────────────┤
│ GET │ / │ (none) │
│ GET │ /users │ (none) │
│ POST │ /users │ (none) │
│ GET │ /users/:id │ (none) │
└────────┴──────────────────────────────┴─────────────────────────────┘
✅ 4 route(s), 0 middleware scope(s) loaded
And GET http://localhost:3000/ returns {"message":"Hello, World!"}.
Route File Naming Convention
| File name | Route |
|---|---|
src/routes/index.get.rs |
GET / |
src/routes/users.get.rs |
GET /users |
src/routes/users/index.post.rs |
POST /users |
src/routes/users/[id].get.rs |
GET /users/:id |
src/routes/users/[id].delete.rs |
DELETE /users/:id |
src/routes/posts/[...slug].get.rs |
GET /posts/*slug (catch-all) |
Rules:
- File name format:
<name>.<method>.rs indexis a special name — it maps to the directory itself (no extra path segment)[param]→ dynamic path parameter[...param]→ catch-all parameter (matches everything after)
Extracting Request Data
Astrea replaces complex Axum extractor signatures with simple function calls:
pub async
Response Helpers
// JSON (application/json)
json?
// Plain text (text/plain)
text
// HTML (text/html)
html
// Redirect (302 Found)
redirect?
// No Content (204)
no_content
// Raw bytes
bytes.content_type
// Streaming
stream
All responses support chaining:
json?
.status
.header
WebSockets & Server-Sent Events (SSE)
Astrea supports WebSockets and SSE natively via route attributes. Simply use #[route(ws)] or #[route(sse)] instead of #[route].
WebSockets (#[route(ws)])
use *;
use ;
pub async
Server-Sent Events (#[route(sse)])
use *;
use ;
use Duration;
pub async
Error Handling
Return errors naturally — they become proper HTTP responses automatically:
pub async
Built-in error variants:
| Method | Status Code |
|---|---|
RouteError::bad_request(msg) |
400 |
RouteError::unauthorized(msg) |
401 |
RouteError::forbidden(msg) |
403 |
RouteError::not_found(msg) |
404 |
RouteError::conflict(msg) |
409 |
RouteError::validation(msg) |
422 |
RouteError::rate_limit(msg) |
429 |
RouteError::custom(StatusCode, msg) |
any |
? on any anyhow-compatible error |
500 |
All errors are returned as JSON: {"error": "...", "status": 404}.
Middleware
Create _middleware.rs files anywhere in the src/routes/ directory. They scope to the folder they live in + all subfolders.
src/routes/
├── _middleware.rs # applies to ALL routes
├── api/
│ ├── _middleware.rs # applies to /api/* (stacks on root)
│ ├── users.get.rs # ← root + api middleware
│ └── public/
│ ├── _middleware.rs # OVERRIDES parent middleware
│ └── health.get.rs # ← public middleware only
Extend mode (default) — stack on parent
// src/routes/_middleware.rs
use *;
Override mode — replace parent middleware
// src/routes/api/public/_middleware.rs
use *;
OpenAPI (Optional)
Enable the openapi feature to get automatic API documentation:
[]
= { = "0.0.1", = ["openapi"] }
Then merge the OpenAPI router:
let app = create_router
.merge;
This gives you:
GET /openapi.json— the OpenAPI 3.0 specGET /swagger— Swagger UI
Application State
Share state across handlers (database pools, config, etc.):
// In handler:
pub async
Full Example
my-api/
├── Cargo.toml
└── src/
├── main.rs
└── routes/
├── _middleware.rs
├── index.get.rs
└── api/
├── _middleware.rs
├── users.get.rs
├── users.post.rs
└── users/
├── [id].get.rs
├── [id].put.rs
└── [id].delete.rs
This generates:
GET /— root pageGET /api/users— list usersPOST /api/users— create userGET /api/users/:id— get user by IDPUT /api/users/:id— update userDELETE /api/users/:id— delete user
Root middleware → all routes. API middleware → /api/* routes.
Why Astrea?
| Astrea | Plain Axum | |
|---|---|---|
| Route definition | Drop a file | Manual .route() calls |
| Handler signature | Always (Event) -> Result<Response> |
Varies per extractor combo |
| Parameter access | get_param(&event, "id") |
Path(id): Path<String> |
| Error handling | Built-in JSON errors | DIY |
| Middleware | File-based scoping | Manual nesting |
| OpenAPI | Auto-generated | Manual or third-party |
AI Agent Support
Astrea provides a built-in guide for AI coding assistants. If you are using an AI agent (like Copilot, Cursor, or Claude) to help you build your application, point them to the agent.md file in the root of the repository. It contains framework-specific rules, architectural context, and coding conventions to ensure your AI assistant writes idiomatic Astrea code.
Minimum Supported Rust Version
Rust 1.85 or later (edition 2024).
License
MIT © TNXG (Asahi Shiori)