Introduction

Logo

summer-rs is application framework written in Rust, inspired by Java's SpringBoot

English | 中文

crates.io Documentation Documentation

summer-rs is an application framework that emphasizes convention over configuration, inspired by Java's SpringBoot. summer-rs provides an easily extensible plug-in system for integrating excellent projects in the Rust community, such as axum, sqlx, sea-orm, etc.

Compared with SpringBoot in java, summer-rs has higher performance and lower memory usage, allowing you to completely get rid of the bloated JVM and travel light.

Features

  • ⚡️ High performance: Benefiting from the awesome rust language, summer-rs has the ultimate performance comparable to C/C++
  • 🛡️ High security: Compared to C/C++, the Rust language used by summer-rs provides memory safety and thread safety.
  • 🔨 Lightweight: The core code of summer-rs does not exceed 5,000 lines, and the binary size of the release version packaged in rust is also small.
  • 🔧 Easy to use: summer-rs provides a clear and concise API and optional Procedural Macros to simplify development.
  • 🔌 Highly extensible: summer-rs uses a highly extensible plug-in model, and users can customize plug-ins to extend program capabilities.
  • ⚙️ Highly configurable: summer-rs uses toml to configure applications and plug-ins to improve application flexibility.

Example

web

use summer::{auto_config, App};
use summer_sqlx::{
    sqlx::{self, Row},
    ConnectPool, SqlxPlugin
};
use summer_web::{get, route};
use summer_web::{
    error::Result, extractor::{Path, Component}, handler::TypeRouter, axum::response::IntoResponse, Router,
    WebConfigurator, WebPlugin,
};
use anyhow::Context;

#[auto_config(WebConfigurator)]
#[tokio::main]
async fn main() {
    App::new()
        .add_plugin(SqlxPlugin)
        .add_plugin(WebPlugin)
        .run()
        .await
}

#[get("/")]
async fn hello_world() -> impl IntoResponse {
    "hello world"
}

#[route("/hello/{name}", method = "GET", method = "POST")]
async fn hello(Path(name): Path<String>) -> impl IntoResponse {
    format!("hello {name}")
}

#[get("/version")]
async fn sqlx_request_handler(Component(pool): Component<ConnectPool>) -> Result<String> {
    let version = sqlx::query("select version() as version")
        .fetch_one(&pool)
        .await
        .context("sqlx query failed")?
        .get("version");
    Ok(version)
}

job

use anyhow::Context;
use summer::{auto_config, App};
use summer_job::{cron, fix_delay, fix_rate};
use summer_job::{extractor::Component, JobConfigurator, JobPlugin};
use summer_sqlx::{
    sqlx::{self, Row},
    ConnectPool, SqlxPlugin,
};
use std::time::{Duration, SystemTime};

#[auto_config(JobConfigurator)]
#[tokio::main]
async fn main() {
    App::new()
        .add_plugin(JobPlugin)
        .add_plugin(SqlxPlugin)
        .run()
        .await;

    tokio::time::sleep(Duration::from_secs(100)).await;
}

#[cron("1/10 * * * * *")]
async fn cron_job(Component(db): Component<ConnectPool>) {
    let time: String = sqlx::query("select TO_CHAR(now(),'YYYY-MM-DD HH24:MI:SS') as time")
        .fetch_one(&db)
        .await
        .context("query failed")
        .unwrap()
        .get("time");
    println!("cron scheduled: {:?}", time)
}

#[fix_delay(5)]
async fn fix_delay_job() {
    let now = SystemTime::now();
    let datetime: sqlx::types::chrono::DateTime<sqlx::types::chrono::Local> = now.into();
    let formatted_time = datetime.format("%Y-%m-%d %H:%M:%S");
    println!("fix delay scheduled: {}", formatted_time)
}

#[fix_rate(5)]
async fn fix_rate_job() {
    tokio::time::sleep(Duration::from_secs(10)).await;
    let now = SystemTime::now();
    let datetime: sqlx::types::chrono::DateTime<sqlx::types::chrono::Local> = now.into();
    let formatted_time = datetime.format("%Y-%m-%d %H:%M:%S");
    println!("fix rate scheduled: {}", formatted_time)
}

component macros

Add dependencies to your Cargo.toml:

[dependencies]
summer = "0.4"
tokio = { version = "1", features = ["full"] }

Simple component registration with #[component] macro:

use summer::component;
use summer::config::Configurable;
use summer::extractor::Config;
use summer::plugin::ComponentRegistry;
use summer::App;
use serde::Deserialize;

// Define configuration
#[derive(Clone, Configurable, Deserialize)]
#[config_prefix = "app"]
struct AppConfig {
    name: String,
}

// Define component
#[derive(Clone)]
struct AppService {
    config: AppConfig,
}

// Use #[component] macro for automatic registration
#[component]
fn app_service(Config(config): Config<AppConfig>) -> AppService {
    AppService { config }
}

#[tokio::main]
async fn main() {
    // Components are automatically registered
    let app = App::new().build().await.unwrap();
    
    // Get registered component
    let service = app.get_component::<AppService>().unwrap();
    println!("App name: {}", service.config.name);
}

The #[component] macro eliminates boilerplate code - no need to manually implement the Plugin trait! Learn more →

Supported plugins

PluginCrateIntegrated WithDescription
summer-websummer-webaxumWeb framework based on Axum
summer-sqlxsummer-sqlxsqlxAsync SQL access
summer-postgressummer-postgresrust-postgresPostgreSQL client integration
summer-sea-ormsummer-sea-ormsea-ormORM support
summer-redissummer-redisredisRedis integration
summer-mailsummer-maillettreEmail sending
summer-jobsummer-jobtokio-cron-schedulerScheduled jobs / Cron
summer-streamsummer-streamsea-streamerStream processing (Redis Streams / Kafka)
summer-opentelemetrysummer-opentelemetryopentelemetryLogging, metrics, and distributed tracing
summer-grpcsummer-grpctonicgRPC services and clients
summer-opendalsummer-opendalopendalUnified object storage and data access
summer-apalissummer-apalisapalisHigh-performance background processing library
summer-sa-tokensummer-sa-tokensa-token-rustSa-Token authentication and authorization

Ecosystem

more>>

Project showcase

Contribution

We also welcome community experts to contribute their own plugins. Contributing →

Help

Click here to view common problems encountered when using summer-rs Help →