#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
pub mod binding;
pub mod bootstrap;
pub mod broadcasting;
pub mod commands;
pub mod facades;
pub mod groups;
pub mod keys;
pub mod notifications;
pub mod observability;
pub mod scheduling;
pub use bootstrap::Rainier;
pub use commands::{
console, KeyGenerateCommand, MigrateCommand, MigrateRollbackCommand, QueueWorkCommand,
RouteListCommand, ServeCommand,
};
pub use facades::Views;
pub use scheduling::{
CommandTask, JobTask, ScheduleExt, ScheduleListCommand, ScheduleRunCommand, ScheduleWorkCommand,
};
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_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;
pub use rainier_container::{facade, Application, Facade, ServiceProvider};
pub use rainier_database::bind_executor;
pub mod prelude {
pub use crate::bootstrap::Rainier;
pub use crate::facades::{
Broadcast, Cache, Config, Crypt, Event, Mail, Middleware, Notify, Queue, Session, Storage,
Url, View, Views, DB,
};
pub use rainier_container::{Application, Container, Facade, ServiceProvider};
pub use rainier_support::{Context as _, Error, ErrorKind, Result};
pub use rainier_config::{AppEnv, Key as ConfigurationKey, Setting as _};
pub use crate::binding::{Bound, BoundAs};
pub use rainier_http::extract::{Bearer, Form, Json, Path, Query, RawBody};
pub use rainier_http::{
Cookie, FromRequest, Html, IntoResponse, Method, Redirect, Request, Response, StatusCode,
};
pub use rainier_cache::{Cache as CacheContract, CacheDriver, CacheExt as _, CacheManager};
pub use rainier_crypt::{EncrypterExt as _, Encryption, SignerExt as _};
pub use rainier_filesystem::{
Filesystem, FilesystemDriver, FilesystemExt as _, LocalFilesystem,
Storage as StorageManager,
};
pub use rainier_middleware::{Middleware as MiddlewareContract, Next, TrustProxies};
pub use rainier_routing::{
GroupAttributes, ParamConstraint, Req, ResourceController, Route, Router,
};
pub use rainier_session::{
Session as SessionBag, SessionDriver, SessionManager, SessionRequestExt as _, StartSession,
};
pub use rainier_validation::{field, FormRequest, Rule, RuleSet, Validated, Validator};
pub use rainier_database::{
BelongsTo, BelongsToMany, Criteria, Database, EntityRepository, HasMany, HasOne, Model,
Paginated, Related, RelatedCounts, Relation, Repository,
};
pub use rainier_orm::Entity;
pub use rainier_auth::{
AuthManager, Authenticatable, AuthenticatedUser, Credentials, Gate, GuardExt as _,
};
pub use rainier_broadcast::{Broadcastable, Broadcasting, Channel as BroadcastChannelName};
pub use rainier_events::Dispatcher;
pub use rainier_mail::{Content, Envelope, MailDriver, Mailable};
pub use rainier_metrics::{Metrics, RecordMetrics};
pub use rainier_notify::{Channels, Notifiable, Notification, Notifier};
pub use rainier_queue::{Job, JobContext, QueueDriver, QueueManager};
pub use rainier_telemetry::Trace;
pub use rainier_view::View as ViewData;
pub use rainier_websocket::{Rooms, Socket, WebSocketHandler, WebSocketRoutes};
pub use async_trait::async_trait;
pub use std::sync::Arc;
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use rainier_http::Method;
#[tokio::test]
async fn an_application_boots_and_serves() {
let app = Rainier::new(".")
.without_facades()
.without_tracing()
.with_routes(|router| {
router.get("/", || async { "hello" }).name("home");
})
.boot()
.await
.expect("boots");
let kernel = app.resolve::<rainier_server::Kernel>().unwrap();
let response =
kernel.handle_request(Request::builder().method(Method::GET).uri("/").build()).await;
assert_eq!(response.status(), StatusCode::OK);
}
#[tokio::test]
async fn the_prelude_covers_a_realistic_controller() {
#[derive(serde::Deserialize)]
struct StorePost {
title: String,
}
#[async_trait]
impl FormRequest for StorePost {
fn rules() -> RuleSet {
vec![field("title", [Rule::Required, Rule::String])]
}
}
async fn store(Validated(post): Validated<StorePost>) -> Result<Response> {
Ok(Response::json(&serde_json::json!({ "title": post.title })))
}
let app = Rainier::new(".")
.without_facades()
.without_tracing()
.with_routes(|router| {
router.post("/posts", store);
})
.boot()
.await
.expect("boots");
let response = app
.resolve::<rainier_server::Kernel>()
.unwrap()
.handle_request(
Request::builder()
.method(Method::POST)
.uri("/posts")
.json(&serde_json::json!({ "title": "Hello" }))
.build(),
)
.await;
assert_eq!(response.status(), StatusCode::OK);
}
#[tokio::test]
async fn a_failed_contract_is_a_422() {
#[derive(serde::Deserialize)]
struct StorePost {
#[allow(dead_code)]
title: String,
}
#[async_trait]
impl FormRequest for StorePost {
fn rules() -> RuleSet {
vec![field("title", [Rule::Required])]
}
}
async fn store(Validated(_): Validated<StorePost>) -> &'static str {
"created"
}
let app = Rainier::new(".")
.without_facades()
.without_tracing()
.with_routes(|router| {
router.post("/posts", store);
})
.boot()
.await
.unwrap();
let response = app
.resolve::<rainier_server::Kernel>()
.unwrap()
.handle_request(
Request::builder()
.method(Method::POST)
.uri("/posts")
.header("accept", "application/json")
.json(&serde_json::json!({}))
.build(),
)
.await;
assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY);
}
}