# Ravel
A **Laravel-inspired Rust web framework** built on Axum, SeaORM, and Tokio — bringing Laravel's developer experience to the Rust ecosystem.
## Quick Start
```bash
# Install the CLI
cargo install ravel-cli
# Create a new project
ravel new MyApp
cd my_app
# Start the dev server
ravel serve
```
```
Ravel running at http://127.0.0.1:3000
```
## Features
### CLI (ravel-cli)
```
ravel new <name> Create a new Ravel project
ravel serve Start the development server
ravel route:list List all registered routes
ravel key:generate Generate an application key
ravel make:controller <n> Scaffold a Controller
ravel make:middleware <n> Scaffold a Middleware
ravel make:model <n> Scaffold a SeaORM entity
ravel make:migration <n> Scaffold a migration
ravel make:seeder <n> Scaffold a Seeder
ravel make:provider <n> Scaffold a ServiceProvider
ravel make:request <n> Scaffold a FormRequest
ravel migrate Run pending migrations
ravel migrate:rollback Rollback migrations
ravel migrate:refresh Rollback all + re-apply
ravel migrate:fresh Drop all tables + re-apply
ravel migrate:status Show migration status
ravel db:seed Run database seeders
```
### Service Container (ravel-core)
- **DI Container** — TypeId-based with singleton, transient factory, and pre-built instance support
- **Freeze mechanism** — `container.freeze()` makes reads thread-safe for concurrent HTTP serving
- **Config repository** — Load `.toml` files from `config/`, access via dot-notation keys (`app.name`, `database.port`)
- **Env override** — `APP_*` environment variables automatically override TOML config values
- **Service Providers** — Two-phase bootstrap (`register` -> `boot`), inspired by Laravel
- **Event dispatcher** — Lightweight publish/subscribe event system
- **Cache** — In-memory TTL cache
```rust
use ravel_core::app::{Application, ServiceProvider};
let app = Application::new()
.load_config("config")?
.register_provider(MyProvider)
.boot()?;
```
### HTTP Layer (ravel-http)
- **Route Builder** — Fluent DSL with method chaining, grouping, and middleware
- **Controller trait** — Organize handlers into controller structs
- **RavelRequest** — Laravel-style request helpers (`req.query("page")`, `req.header("auth")`)
- **ResponseBuilder** — Fluent response construction (`response().json(data)`, `response().redirect("/")`)
- **FormRequest** — Automatic JSON parsing + validation with 422 responses
- **Validation** — Rules: Required, Min, Max, Email, Regex, In
- **Middleware** — Built-in: error handler, request logger, CORS builder, Bearer token auth
- **Unified error handling** — `RavelError` enum implements `IntoResponse`, handlers can use `?`
- **ServerBuilder** — Graceful shutdown via Ctrl+C, shared state injection
- **View engine** — Tera template rendering
```rust
use ravel_http::route::Route;
use ravel_http::middleware;
let router = Route::new()
.get("/", || async { "Hello, Ravel!" })
.post("/users", create_user)
.group("/admin", |r| {
r.get("/dashboard", admin_dashboard)
.get("/users", admin_users)
})
.middleware(middleware::log_requests)
.build();
```
```rust
use ravel_http::error::RavelError;
use ravel_http::response::response;
async fn show_user(id: u32) -> Result<impl IntoResponse, RavelError> {
let user = find_user(id).ok_or(RavelError::not_found("User not found"))?;
Ok(response().json(user)?)
}
```
### Database (ravel-db-core + ravel-db-seaorm)
- **Multi-connection** — Named connections from `config/database.toml`
- **Lazy connection** — Thread-safe, pools connections on first use
- **Migration runner** — CLI-driven with SeaORM migrations
- **Pagination** — `Page<T>` with `has_more()`, `last_page()`, `count()`
- **Decoupled** — `ravel-db-core` defines traits; `ravel-db-seaorm` is the SeaORM implementation
```toml
# config/database.toml
[default]
driver = "postgres"
host = "localhost"
port = 5432
database = "myapp"
username = "user"
password = "secret"
max_connections = 20
min_connections = 5
```
```rust
use ravel_db_seaorm::connection::ConnectionManager;
let manager = ConnectionManager::from_config("config")?;
let db = manager.connect("default").await?;
```
### Job Queue (ravel-support)
- **Async jobs** — `Job` trait with `async fn handle(&self) -> Result<()>`
- **Pluggable drivers** — In-memory (default), Redis, and DB backends
- **Retry with backoff** — Configure `max_attempts()` per job type
- **Dead-letter queue** — Failed jobs tracked with error details and retry support
- **Delayed dispatch** — `queue.dispatch_later(job, Duration::hours(1))`
- **Task scheduler** — Cron-style recurring tasks with `SchedulerDriver` trait
- **File storage** — `Storage` facade with `LocalDisk` implementation
- **Derive macro** — `#[derive(Job)]` with `#[job(name = "...", queue = "...", max_attempts = N)]`
```rust
use ravel_support::queue::{Job, Queue};
use ravel_macros::Job;
#[derive(Serialize, Deserialize, Job)]
#[job(name = "send_welcome", queue = "mail", max_attempts = 5)]
struct SendWelcomeEmail { user_id: u32 }
#[async_trait]
impl Job for SendWelcomeEmail {
async fn handle(&self) -> Result<()> {
// Send the email...
Ok(())
}
}
```
## Project Structure
```
ravel/
├── crates/
│ ├── ravel-cli/ CLI tool (clap)
│ ├── ravel-core/ DI container, config, env, events, cache
│ ├── ravel-http/ Route builder, server, middleware, request/response
│ ├── ravel-db-core/ Database abstraction traits
│ ├── ravel-db-seaorm/ SeaORM implementation
│ ├── ravel-generator/ Code scaffolding (Tera templates)
│ ├── ravel-support/ Queue, scheduler, storage
│ ├── ravel-macros/ Proc-macros (#[derive(Job)])
│ └── ravel-test/ TestClient and response assertions
└── testblog/ Reference application + integration tests
```
## Requirements
- Rust 1.82+ (edition 2024)
- PostgreSQL / MySQL / SQLite (for database features)
## License
MIT