Skip to main content

Crate modo

Crate modo 

Source
Expand description

§modo

A Rust web framework for small monolithic apps. Single crate, zero proc macros, built on axum 0.8 with libsql (SQLite) for persistence. Handlers are plain async fn, routes use axum::Router directly, services are wired explicitly in main(), and database queries use raw libsql. Current version: 0.11.0.

§Modules

Foundation:

ModulePurpose
configYAML config loader with ${VAR} / ${VAR:default} env substitution
errorFramework Error type (status + message + source + code) and Result alias
runtimeGraceful-shutdown Task abstraction used by run!
serverHTTP server bootstrap with bind, listen, and shutdown wiring
serviceTyped service Registry and AppState

Persistence & I/O:

ModulePurpose
cacheIn-memory LRU cache with TTL
dblibsql/SQLite Database handle, migrations, query helpers
storageS3-compatible object storage with ACL and upload-from-URL

Request lifecycle:

ModulePurpose
clientHTTP client with shared connection pool
cookieSigned/private cookie helpers and config
extractorRequest extractors with auto-sanitisation (JSON, form, query, multipart)
flashSigned read-once cookie flash messages
ipClientIp extractor with trusted-proxy resolution
middlewareTower middleware (CORS, CSRF, rate limit, security headers, etc.)
sseServer-Sent Events with named broadcast channels

Identity & multi-tenancy:

ModulePurpose
authSessions (cookie + JWT), passwords, TOTP, OAuth2, API keys, RBAC roles
tenantMulti-tenancy via subdomain, header, path, or custom resolver
tierSubscription-tier gating

Background work:

ModulePurpose
cron5/6-field cron scheduler
jobSQLite-backed job queue with retries, scheduling, and idempotent enqueue

Application services:

ModulePurpose
emailMarkdown-to-HTML email rendering with SMTP
i18nICU plural rules, locale resolution, translation store
qrcodeQR code rendering (SVG / PNG)
templateMiniJinja with i18n, HTMX detection, flash integration
webhookOutbound webhook delivery with Standard Webhooks signing

Observability:

ModulePurpose
auditStructured audit-log writer
health/_live and /_ready endpoint handlers
tracingTracing/Sentry subscriber setup and request-trace middleware

Network primitives:

ModulePurpose
dnsTXT/CNAME verification for custom-domain validation
embedEmbed.ly-style URL preview
geolocationMaxMind GeoIP2 lookup with middleware

Utilities:

ModulePurpose
encodingBase64url, hex, and other encoding helpers
idid::ulid() (26-char) and id::short() (13-char base36)
sanitizeSanitize trait used by extractors
validateValidate, Validator, ValidationError

Virtual flat-indexes (cross-module re-exports for discoverability):

ModulePurpose
extractorsEvery public request extractor, gathered from across the crate
guardsEvery route-level gating layer applied via .route_layer()
middlewaresEvery public middleware constructor
preludeGlob-import bundle for handler modules

Test-only (gated behind the test-helpers feature):

ModulePurpose
testingTestDb, TestApp, TestSession, and in-memory/stub backends

§Re-exports

Crate-root re-exports for the items used in almost every program:

  • Error — framework error type (HTTP status + message + optional source/code)
  • Resultstd::result::Result<T, Error> alias
  • Config — top-level application configuration (config::Config)
  • run! — macro that waits for SIGTERM/SIGINT then shuts down each supplied Task in declaration order

Plus the four dependency crates whose types appear in handler signatures, so you don’t need to pin matching versions yourself:

  • axum — router, extractors, responses
  • serdeSerialize / Deserialize derives
  • serde_json — JSON values and macros
  • tokio — runtime, tasks, sync primitives

§Quick start

Add to Cargo.toml:

[dependencies]
modo = { package = "modo-rs", version = "0.11.0" }

[dev-dependencies]
modo = { package = "modo-rs", version = "0.11.0", features = ["test-helpers"] }

Minimal application:

use modo::axum::{Router, routing::get};
use modo::{Config, Result};

async fn hello() -> &'static str {
    "Hello, modo!"
}

#[tokio::main]
async fn main() -> Result<()> {
    let config: Config = modo::config::load("config/")?;
    let app = Router::new().route("/", get(hello));
    let server = modo::server::http(app, &config.server).await?;
    modo::run!(server).await
}

Inside a handler module, pull in the common handler-time types with:

use modo::prelude::*;

§Features

Every production module is always compiled — there are no per-capability cargo features. The only flag is test-helpers, which exposes in-memory backends and test harnesses; enable it in your [dev-dependencies].

FeaturePurpose
test-helpersEnables the testing module (TestDb, TestApp, TestSession) and all in-memory/stub backends

Re-exports§

pub use config::Config;
pub use error::Error;
pub use error::Result;
pub use axum;
pub use serde;
pub use serde_json;
pub use tokio;

Modules§

audit
modo::audit
auth
modo::auth
cache
modo::cache
client
modo::client
config
modo::config
cookie
modo::cookie
cron
modo::cron
db
modo::db
dns
modo::dns
email
modo::email
embed
modo::embed
encoding
modo::encoding
error
modo::error
extractor
modo::extractor
extractors
Flat index of every axum extractor modo ships.
flash
modo::flash
geolocation
modo::geolocation
guards
Flat index of every route-level gating layer.
health
modo::health
i18n
modo::i18n
id
modo::id
ip
modo::ip
job
modo::job
middleware
modo::middleware
middlewares
Flat index of every Tower Layer modo ships.
prelude
Handler-time prelude.
qrcode
modo::qrcode
runtime
modo::runtime
sanitize
modo::sanitize
server
modo::server
service
modo::service
sse
modo::sse
storage
modo::storage
template
modo::template
tenant
modo::tenant
tier
modo::tier
tracing
modo::tracing
validate
modo::validate
webhook
modo::webhook

Macros§

run
Waits for a shutdown signal and then shuts down each task in order.