Skip to main content

Crate rainier_framework

Crate rainier_framework 

Source
Expand description

§Rainier

An MVC framework for Rust, built on the Rainier ORM DBAL.

Rainier takes the structures server-side MVC frameworks converge on — a service container, service providers, a router with named routes and middleware groups, form requests, guards, jobs, mailables, facades, events — and gives each one a Rust shape rather than a transliteration from another language. Where convention and the language disagree, the disagreement is resolved in Rust’s favour and the reason is written down in the module that made the call.

use rainier_framework::prelude::*;

async fn index() -> &'static str {
    "Hello from Rainier"
}

#[tokio::main]
async fn main() -> Result<()> {
    let app = Rainier::new(".")
        .with_routes(|router| {
            router.get("/", index).name("home");
        })
        .boot()
        .await?;

    rainier_framework::console("rainier").run_from_env(&app).await;
    Ok(())
}

§The crates

Each component is its own crate, and depends only on what it genuinely needs — so an application that wants the queue but not HTTP pays for neither the router nor hyper.

CrateWhat it owns
supportthe error type, futures, type-maps, string inflection
rainier_ormthe DBAL: entities, queries, DDL, sharding, the Executor port
containerthe IoC container, service providers, lifecycle hooks, facades
configthe config repository and .env
eventsthe event dispatcher — the hook bus
httprequests, responses, cookies, uploads, extractors
middlewarethe handle(request, next) pipeline and the built-in set
routingroute declaration, groups, resources, URL generation
validationrules, the validator, and request contracts
viewthe template engine
databaseRainier ORM integration, models, repositories
authguards, user providers, hashing, gates
queuejobs, queue drivers, the worker
mailmailables, the mailer, transports
serverthe HTTP kernel and the hyper server
consolethe console and its commands
cachethe cache port and its drivers
cryptencryption and message signing
driversshared Redis, Memcached and AWS transports
filesystemfile storage: local, memory, S3/R2
notifynotifications: a message to a recipient, over their channels
schedulercron expressions, the schedule, and its atomic locks
sessionthe session bag, its store, and the middleware

§Where Rainier departs from MVC convention

  • Middleware is named, not typed, at the route. .middleware("auth") keeps routing from depending on auth — see middleware::registry.
  • The auth manager is generic over the user model rather than erasing it behind dyn Authenticatable, because an application wants its own type back. See auth.
  • Model hooks can veto but not mutate. Several listeners mutating one row in registration order would make the outcome depend on wiring; see database::model.
  • Request bodies are buffered. That is what lets request.input(..) be synchronous, as $request->input() is; see http::body.
  • Configuration is typed at both ends. config('cache.driver') has a magic string for the path and another for the value. Rainier has keys::CACHE_DRIVER and a cache::CacheDriver enum, so a misspelled path does not compile and a misspelled driver fails the boot rather than silently caching in-process. See keys.

§The Rainier ORM Send story

Rainier ORM used to hold a sea_query statement across its awaits, which made every repo:: future !Send — unusable inside a handler the server will tokio::spawn, since sea_query statements hold Rc. That is fixed upstream: statements are built and dropped in a scope that ends before the await, and Query’s terminals consume self outside their async block (an async fn captures every argument whether or not the body moves it out).

So repo:: and the query builder work directly against a database::Database. Rainier still renders its repository SQL synchronously through database::statement — now a design choice that keeps shard routing and dialect rendering explicit at the framework seam, rather than a workaround.

One exception remains: rainier_orm::migrate::Migrator::run boxes its steps behind dyn, so its future cannot be Send on stable. database::Migrator is the Send alternative — it renders DDL synchronously and executes plain strings, and its Migration contract makes every step declare how to undo itself.

Re-exports§

pub use bootstrap::Rainier;
pub use commands::console;
pub use commands::KeyGenerateCommand;
pub use commands::MigrateCommand;
pub use commands::MigrateRollbackCommand;
pub use commands::QueueWorkCommand;
pub use commands::RouteListCommand;
pub use commands::ServeCommand;
pub use facades::Views;
pub use health::Health;
pub use health::Report as HealthReport;
pub use limits::RateLimits;
pub use queued_listeners::DispatcherExt;
pub use queued_listeners::FromEvent;
pub use scheduling::CommandTask;
pub use scheduling::JobTask;
pub use scheduling::ScheduleExt;
pub use scheduling::ScheduleListCommand;
pub use scheduling::ScheduleRunCommand;
pub use scheduling::ScheduleWorkCommand;
pub use signed::SignedUrls;
pub use signed::ValidateSignature;
pub use testing::TestApp;
pub use testing::TestResponse;
pub use rainier_auth as auth;
pub use rainier_broadcast as broadcast;
pub use rainier_cache as cache;
pub use rainier_config as config;
pub use rainier_console as console_kernel;
pub use rainier_container as container;
pub use rainier_crypt as crypt;
pub use rainier_database as database;
pub use rainier_drivers as drivers;
pub use rainier_events as events;
pub use rainier_filesystem as filesystem;
pub use rainier_http as http;
pub use rainier_http_client as http_client;
pub use rainier_mail as mail;
pub use rainier_metrics as metrics;
pub use rainier_middleware as middleware;
pub use rainier_notify as notify;
pub use rainier_openapi as openapi;
pub use rainier_queue as queue;
pub use rainier_routing as routing;
pub use rainier_scheduler as scheduler;
pub use rainier_server as server;
pub use rainier_session as session;
pub use rainier_support as support;
pub use rainier_telemetry as telemetry;
pub use rainier_validation as validation;
pub use rainier_view as view;
pub use rainier_websocket as websocket;
pub use rainier_orm;

Modules§

binding
Route-model binding — an action parameter that is the looked-up model rather than its id.
bootstrap
Bootstrapping — Rainier, the builder that assembles an application.
broadcasting
The half of broadcasting that needs HTTP: the authorisation endpoint, the socket header, and the notification channel.
commands
The commands Rainier ships — route:list, serve, migrate, queue:work, key:generate.
facade
Facades — static proxies onto container-resolved services.
facades
The facades — static proxies onto container-resolved services.
groups
The middleware groups Rainier ships — web and api, as functions rather than as keys in a map.
health
Health checks — Health and the endpoint that renders them.
kafka
Building the Kafka pieces from configuration.
keys
The configuration keys Rainier itself reads — a typed index of the tree.
limits
Rate limits that survive a second replica — RateLimits and shared.
notifications
The notification channel that needs a database.
observability
Metrics, tracing and the OpenAPI document, built from configuration.
prelude
Everything an application file usually wants in scope.
queued_listeners
Listeners that go on the queue — DispatcherExt and FromEvent.
relay
Relaying broadcasts back into the sockets this process holds.
scheduling
Scheduling — the tasks and commands that need more than the scheduler crate depends on.
signed
Signed routes — SignedUrls and ValidateSignature.
testing
A test harness — TestApp and TestResponse.

Macros§

bind_executor
Writes the Connection impl for a concrete Rainier ORM Executor.
facade
Declare a facade type and its Facade impl.
param_key
Declare a route-parameter name for BoundAs.

Structs§

Application
The application: a Container with a boot lifecycle, an environment, and a filesystem layout.

Traits§

Facade
A static proxy onto a container-resolved service.
ServiceProvider
A bundle of related bindings and their boot-time wiring.