### Rust: Application Runners with Springtime Source: https://context7.com/krojew/springtime/llms.txt Demonstrates building applications with automatic discovery and execution of application runners using the Springtime framework in Rust. Runners are components that execute logic when the application starts, with priorities determining execution order. This example includes database migration and server startup runners. ```rust use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime::runner::ApplicationRunner; use springtime_di::{Component, component_alias}; use springtime_di::instance_provider::ErrorPtr; // Runners execute when application starts #[derive(Component)] struct DatabaseMigrationRunner; #[component_alias] impl ApplicationRunner for DatabaseMigrationRunner { fn run(&self) -> BoxFuture<'_, Result<(), ErrorPtr>> { async { println!("Running database migrations..."); // Migration logic here Ok(()) } .boxed() } // Higher priority runs first fn priority(&self) -> i8 { 10 } } #[derive(Component)] struct ServerStartupRunner; #[component_alias] impl ApplicationRunner for ServerStartupRunner { fn run(&self) -> BoxFuture<'_, Result<(), ErrorPtr>> { async { println!("Starting server..."); // Server startup logic Ok(()) } .boxed() } fn priority(&self) -> i8 { 0 } } #[tokio::main] async fn main() { // Framework discovers all ApplicationRunner implementations let mut application = application::create_default() .expect("Unable to create application"); // Runs all runners in priority order (higher priority first) application.run().await.expect("Error running application"); // Output: // Running database migrations... // Starting server... } ``` -------------------------------- ### Rust Basic Usage of Springtime Web Axum with Controllers Source: https://github.com/krojew/springtime/blob/master/springtime-web-axum/README.md Demonstrates the basic usage of Springtime Web Axum by defining a domain service, a controller, and running the application. It showcases dependency injection for the service within the controller and defines two routes: a root path and a dynamic user path. Errors are unwrapped for simplicity in this example. ```rust use axum::extract::Path; use springtime::application; use springtime_di::instance_provider::ComponentInstancePtr; use springtime_di::{injectable, Component, component_alias}; use springtime_web_axum::controller; // injectable example trait representing a domain service #[injectable] trait DomainService { fn get_important_message(&self, user: &str) -> String; } // concrete service implementation #[derive(Component)] struct ExampleDomainService; // register ExampleDomainService as providing dyn DomainService #[component_alias] impl DomainService for ExampleDomainService { fn get_important_message(&self, user: &str) -> String { format!("Hello {}!", user) } } // create a struct which will serve as our Controller - this implies it needs to be a Component for // the dependency injection to work #[derive(Component)] struct ExampleController { // inject the domain service (alternatively, inject concrete type instead of a trait) service: ComponentInstancePtr, } // mark the struct as a Controller - this will scan all functions for the controller attributes and // create axum handlers out of them #[controller] impl ExampleController { // this function will respond to GET request for http://localhost/ (or any network interface) #[get("/")] async fn hello_world(&self) -> &'static str { "Hello world!" } // all axum features are available for controllers #[get("/{user}")] async fn hello_user(&self, Path(user): Path) -> String { // delegate work to our domain service self.service.get_important_message(&user) } } // note: for the sake of simplicity, errors are unwrapped, rather than gracefully handled #[tokio::main] async fn main() { let mut application = application::create_default().expect("unable to create application"); // run our server with default configuration - requests should be forwarded to ExampleController application.run().await.expect("error running application"); } ``` -------------------------------- ### Rust: Handling Multiple Implementations with Springtime Source: https://context7.com/krojew/springtime/llms.txt Illustrates how to manage multiple implementations of the same trait in Rust using Springtime DI. This example shows how to designate a primary implementation and inject specific implementations by name. It depends on the `springtime-di` crate. ```rust use springtime_di::{Component, injectable, component_alias}; use springtime_di::factory::ComponentFactoryBuilder; use springtime_di::instance_provider::{ComponentInstancePtr, TypedComponentInstanceProvider}; #[injectable] trait Logger { fn log(&self, message: &str); } // Mark one implementation as primary #[derive(Component)] struct ConsoleLogger; #[component_alias(primary)] impl Logger for ConsoleLogger { fn log(&self, message: &str) { println!("[CONSOLE] {}", message); } } // Give component a custom name for targeted injection #[derive(Component)] #[component(names = ["file_logger"])] struct FileLogger; #[component_alias] impl Logger for FileLogger { fn log(&self, message: &str) { println!("[FILE] {}", message); } } #[derive(Component)] struct LoggingService { // Injects primary implementation (ConsoleLogger) primary_logger: ComponentInstancePtr, // Injects specific named implementation #[component(name = "file_logger")] file_logger: ComponentInstancePtr, } impl LoggingService { fn log_everywhere(&self, msg: &str) { self.primary_logger.log(msg); self.file_logger.log(msg); } } fn main() { let mut factory = ComponentFactoryBuilder::new() .expect("Failed to initialize factory") .build(); let service = factory .primary_instance_typed::() .expect("Failed to create service"); service.log_everywhere("Test message"); // Output: // [CONSOLE] Test message // [FILE] Test message } ``` -------------------------------- ### Rust: Component Scopes - Singleton vs Prototype with Springtime DI Source: https://context7.com/krojew/springtime/llms.txt Explains and demonstrates component scopes (singleton and prototype) in Rust using Springtime DI. Singleton components are shared across the application, while prototype components create a new instance for each injection. This example requires the `springtime_di` crate. ```rust use springtime_di::{Component, injectable, component_alias}; use springtime_di::factory::ComponentFactoryBuilder; use springtime_di::instance_provider::{ComponentInstancePtr, TypedComponentInstanceProvider, ErrorPtr}; use std::sync::{Arc, Mutex}; #[injectable] trait Counter { fn increment(&self) -> i32; fn get(&self) -> i32; } // Singleton scope (default) - shared across application #[derive(Component)] struct GlobalCounter { value: Mutex, } #[component_alias] impl Counter for GlobalCounter { fn increment(&self) -> i32 { let mut val = self.value.lock().unwrap(); *val += 1; *val } fn get(&self) -> i32 { *self.value.lock().unwrap() } } // Prototype scope - new instance for each injection #[derive(Component)] #[component( constructor = "RequestCounter::new", scope = "PROTOTYPE", names = ["request_counter"] )] struct RequestCounter { #[component(ignore)] value: Mutex, } impl RequestCounter { fn new() -> Result { Ok(Self { value: Mutex::new(0), }) } } #[component_alias] impl Counter for RequestCounter { fn increment(&self) -> i32 { let mut val = self.value.lock().unwrap(); *val += 1; *val } fn get(&self) -> i32 { *self.value.lock().unwrap() } } #[derive(Component)] struct CounterService { // Same instance shared everywhere global: ComponentInstancePtr, // New instance for each CounterService #[component(name = "request_counter")] request: ComponentInstancePtr, } fn main() { let mut factory = ComponentFactoryBuilder::new() .expect("Failed to initialize factory") .build(); let service1 = factory .primary_instance_typed::() .expect("Failed to create service1"); let service2 = factory .primary_instance_typed::() .expect("Failed to create service2"); service1.global.increment(); service2.global.increment(); println!("Global counter: {}", service1.global.get()); // 2 service1.request.increment(); service2.request.increment(); println!("Request counter 1: {}", service1.request.get()); // 1 println!("Request counter 2: {}", service2.request.get()); // 1 } ``` -------------------------------- ### Rust: Web Controllers with Axum and Springtime Source: https://context7.com/krojew/springtime/llms.txt Illustrates creating HTTP endpoints using the controller pattern with automatic routing and dependency injection in Rust, integrating Axum with the Springtime framework. The `@controller` macro simplifies handler creation, and routes are automatically registered. This example includes handlers for various HTTP methods and parameter types. ```rust use axum::extract::{Path, Query}; use axum::Json; use serde::{Deserialize, Serialize}; use springtime::application; use springtime_di::Component; use springtime_web_axum::controller; #[derive(Component)] struct UserController; #[derive(Deserialize)] struct CreateUserRequest { username: String, email: String, } #[derive(Serialize)] struct UserResponse { id: u64, username: String, email: String, } // Controller macro creates Axum handlers from methods #[controller] impl UserController { // GET / returns plain text #[get("/")] async fn index(&self) -> &'static str { "User API v1" } // GET /{id} with path parameter #[get("/{id}")] async fn get_user(&self, Path(id): Path) -> Json { Json(UserResponse { id, username: format!("user{}", id), email: format!("user{}@example.com", id), }) } // POST / with JSON body #[post("/")] async fn create_user(&self, Json(req): Json) -> Json { Json(UserResponse { id: 1, username: req.username, email: req.email, }) } // GET /search with query parameters #[get("/search")] async fn search_users( &self, Query(params): Query> ) -> String { format!("Searching with params: {:?}", params) } } #[tokio::main] async fn main() { let mut application = application::create_default() .expect("Unable to create application"); // Server starts on http://0.0.0.0:8080 by default // Routes automatically registered: // GET / // GET /{id} // POST / // GET /search application.run().await.expect("Error running application"); } ``` -------------------------------- ### Rust Basic Dependency Injection with Springtime Source: https://github.com/krojew/springtime/blob/master/springtime-di/README.md Demonstrates the fundamental usage of the 'springtime-di' crate for dependency injection in Rust. It shows how to define traits, implement components, alias components to traits, and inject dependencies into other components. This example requires the 'springtime-di' crate. ```rust use springtime_di::factory::ComponentFactoryBuilder; use springtime_di::instance_provider::{ComponentInstancePtr, TypedComponentInstanceProvider}; use springtime_di::{component_alias, injectable, Component}; // this is a trait we would like to use in our component #[injectable] trait TestTrait { fn foo(&self); } // this is a dependency which implements the above trait and also is an injectable component #[derive(Component)] struct TestDependency; // we're telling the framework to provide TestDependency when asked for dyn TestTrait #[component_alias] impl TestTrait for TestDependency { fn foo(&self) { println!("Hello world!"); } } // this is another component, but with a dependency #[derive(Component)] struct TestComponent { // the framework will know how to inject dyn TestTrait, when asked for TestComponent (Send + Sync are only needed // with the "threadsafe" feature) // more details are available in the documentation dependency: ComponentInstancePtr, // alternatively, you can inject the concrete type // dependency: ComponentInstancePtr, } impl TestComponent { fn call_foo(&self) { self.dependency.foo(); } } // note: for the sake of simplicity, errors are unwrapped, rather than gracefully handled fn main() { // components are created by a ComponentFactory // for convenience, ComponentFactoryBuilder can be used to create the factory with a reasonable // default configuration let mut component_factory = ComponentFactoryBuilder::new() .expect("error initializing ComponentFactoryBuilder") .build(); let component = component_factory .primary_instance_typed::() .expect("error creating TestComponent"); // prints "Hello world!" component.call_foo(); } ``` -------------------------------- ### Conditional Component Registration in Rust Source: https://context7.com/krojew/springtime/llms.txt Register components conditionally based on runtime checks using condition expressions. This example shows how to conditionally register an InMemoryCache if a Redis cache is unavailable, using a custom function 'should_use_in_memory_cache'. Dependencies include 'springtime_di'. ```rust use springtime_di::{Component, injectable, component_alias}; use springtime_di::component_registry::conditional::{ConditionMetadata, Context}; use springtime_di::factory::ComponentFactoryBuilder; use springtime_di::instance_provider::{ComponentInstancePtr, TypedComponentInstanceProvider}; #[injectable] trait Cache { fn get(&self, key: &str) -> Option; } #[derive(Component)] struct RedisCache; #[component_alias] impl Cache for RedisCache { fn get(&self, key: &str) -> Option { println!("Using Redis cache"); Some(format!("redis:{}", key)) } } // Only register if Redis is unavailable #[derive(Component)] #[component(condition = "should_use_in_memory_cache")] struct InMemoryCache; fn should_use_in_memory_cache( _context: &dyn Context, _metadata: ConditionMetadata, ) -> bool { // Check if Redis connection is available std::env::var("REDIS_URL").is_err() } #[component_alias] impl Cache for InMemoryCache { fn get(&self, key: &str) -> Option { println!("Using in-memory cache"); Some(format!("memory:{}", key)) } } #[derive(Component)] struct CacheService { cache: ComponentInstancePtr, } fn main() { // Without REDIS_URL set, InMemoryCache will be registered let mut factory = ComponentFactoryBuilder::new() .expect("Failed to initialize factory") .build(); let service = factory .primary_instance_typed::() .expect("Failed to create service"); println!("{:?}", service.cache.get("key1")); // Output: Using in-memory cache // Some("memory:key1") } ``` -------------------------------- ### Component Field Defaults and Custom Initialization in Rust Source: https://context7.com/krojew/springtime/llms.txt Initialize component fields with default values or custom expressions using attributes like #[component(default = "...")]. This example shows setting a default host from an environment variable or a fallback, a default port using the Default trait, and a custom default timeout. ```rust use springtime_di::Component; use springtime_di::factory::ComponentFactoryBuilder; use springtime_di::instance_provider::TypedComponentInstanceProvider; #[derive(Component)] struct Configuration { // Use custom initialization function #[component(default = "default_host")] host: String, // Use Default trait implementation #[component(default)] port: u16, // Normal injection still works #[component(default = "default_timeout")] timeout_secs: u64, } fn default_host() -> String { std::env::var("APP_HOST").unwrap_or_else(|_| "localhost".to_string()) } fn default_timeout() -> u64 { 30 } fn main() { let mut factory = ComponentFactoryBuilder::new() .expect("Failed to initialize factory") .build(); let config = factory .primary_instance_typed::() .expect("Failed to create Configuration"); println!("Host: {}", config.host); // localhost println!("Port: {}", config.port); // 0 (default u16) println!("Timeout: {}", config.timeout_secs); // 30 } ``` -------------------------------- ### Embed SQL Migrations and Define Custom Migration Source - Rust Source: https://github.com/krojew/springtime/blob/master/springtime-migrate-refinery/README.md This snippet demonstrates how to embed SQL migrations from a specified directory using `embed_migrations!` and how to define a custom migration source that provides migrations programmatically. It sets up an example migration and registers it with the dependency injection system. This is useful for managing database schema evolution within a Rust application using the Springtime framework. ```Rust use refinery_core::Runner; use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime_di::instance_provider::ErrorPtr; use springtime_migrate_refinery::migration::embed_migrations; use springtime_migrate_refinery::runner::MigrationRunnerExecutor; // this is all that's needed to embed sql migrations from the given folder (the default path is // "migrations")embed_migrations!("examples/migrations"); // this is a migration source, which can provide migrations from code, instead of sql files #[derive(Component)] struct ExampleMigrationSource; // register the source with dependency injection #[component_alias] impl MigrationSource for ExampleMigrationSource { fn migrations(&self) -> Result, ErrorPtr> { Migration::unapplied("V00__test", "CREATE TABLE test (id INTEGER PRIMARY KEY);") .map(|migration| vec![migration]) .map_err(|error| Arc::new(error) as ErrorPtr) } } // refinery migration runner needs a concrete DB client to run - this necessitates an abstraction // layer; please see MigrationRunnerExecutor for details struct ExampleMigrationRunnerExecutor; impl MigrationRunnerExecutor for ExampleMigrationRunnerExecutor { fn run_migrations(&self, _runner: &Runner) -> BoxFuture<'_, Result<(), ErrorPtr>> { // run migrations here with the given runner async { Ok(()) }.boxed() } } // note: for the sake of simplicity, errors are unwrapped, rather than gracefully handled #[tokio::main] async fn main() { // create our application, which will run refinery migration runner before other runners let mut application = application::create_default().expect("unable to create default application"); // will run migrations from the "migrations" folder if MigrationRunnerExecutor(s) are available application.run().await.expect("error running application"); } ``` -------------------------------- ### Initialize Sample Product Data Source: https://context7.com/krojew/springtime/llms.txt This Rust function initializes sample product data using the repository's save method. It demonstrates creating 'Laptop' and 'Mouse' products with specific details. The function assumes the existence of a `repository` and a `Product` struct. ```rust fn run(&self) -> BoxFuture<'_, Result<(), ErrorPtr>> { async { self.repository.save(Product { id: 0, name: "Laptop".to_string(), price: 999.99, stock: 10, }).unwrap(); self.repository.save(Product { id: 0, name: "Mouse".to_string(), price: 29.99, stock: 50, }).unwrap(); println!("Sample data initialized"); Ok(()) } .boxed() } ``` -------------------------------- ### Run Springtime Application Source: https://context7.com/krojew/springtime/llms.txt This Rust code snippet shows how to create and run a Springtime application. It uses `tokio::main` to establish an asynchronous runtime and `application::create_default()` to instantiate the application. The comments indicate the available API endpoints after the application is running. ```rust #[tokio::main] async fn main() { let mut application = application::create_default() .expect("Unable to create application"); // API available at: // GET /api/products // GET /api/products/{id} // POST /api/products // PUT /api/products/{id}/stock/{stock} // DELETE /api/products/{id} application.run().await.expect("Error running application"); } ``` -------------------------------- ### Rust: Load Configuration from Files and Environment Variables Source: https://context7.com/krojew/springtime/llms.txt This Rust code snippet shows how to load application configuration using Springtime. It demonstrates reading from a default JSON file (e.g., 'springtime.json') and overriding settings with environment variables. It also includes a custom configuration provider that reads server host and port from environment variables. ```rust use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime_di::{Component, component_alias}; use springtime_di::instance_provider::ErrorPtr; use springtime::config::{ApplicationConfig, ApplicationConfigProvider}; use springtime_web_axum::config::{ServerConfig, WebConfig, WebConfigProvider}; // Default configuration reads from springtime.json: // { // "install_tracing_logger": true, // "web": { // "servers": { // "default": { // "listen_address": "0.0.0.0:8080" // } // } // }, // "migration": { // "run_migrations_on_start": true, // "abort_divergent": true, // "abort_missing": true // } // } // Environment variables override file config: // SPRINGTIME_INSTALL_TRACING_LOGGER=false // SPRINGTIME_WEB_SERVERS_DEFAULT_LISTEN_ADDRESS=127.0.0.1:3000 // Custom config provider #[derive(Component)] #[component(constructor = "AppConfig::load")] struct AppConfig { #[component(ignore)] app_config: ApplicationConfig, #[component(ignore)] web_config: WebConfig, } impl AppConfig { fn load() -> BoxFuture<'static, Result> { async { let mut app_config = ApplicationConfig::default(); let mut web_config = WebConfig::default(); // Read from environment or use defaults let host = std::env::var("SERVER_HOST") .unwrap_or_else(|_| "0.0.0.0".to_string()); let port = std::env::var("SERVER_PORT") .unwrap_or_else(|_| "8080".to_string()); app_config.install_tracing_logger = std::env::var("ENABLE_LOGGING") .map(|v| v.parse().unwrap_or(true)) .unwrap_or(true); let mut server_config = ServerConfig::default(); server_config.listen_address = format!("{}:{}", host, port); web_config.servers.insert("default".to_string(), server_config); Ok(Self { app_config, web_config, }) } .boxed() } } #[component_alias] impl ApplicationConfigProvider for AppConfig { fn config(&self) -> BoxFuture<'_, Result<&ApplicationConfig, ErrorPtr>> { async { Ok(&self.app_config) }.boxed() } } #[component_alias] impl WebConfigProvider for AppConfig { fn config(&self) -> BoxFuture<'_, Result<&WebConfig, ErrorPtr>> { async { Ok(&self.web_config) }.boxed() } } #[tokio::main] async fn main() { // Configuration loaded automatically let mut application = application::create_default() .expect("Unable to create application"); application.run().await.expect("Error running application"); } ``` -------------------------------- ### Application Framework with Runners Source: https://context7.com/krojew/springtime/llms.txt This section details how to build applications with automatic discovery and execution of application runners in Springtime. ```APIDOC ## Application Framework with Runners Build applications with automatic discovery and execution of application runners. Runners execute when the application starts. They can be defined as components and implement the `ApplicationRunner` trait. The framework discovers all `ApplicationRunner` implementations and runs them in priority order (higher priority first). ### Example ```rust use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime::runner::ApplicationRunner; use springtime_di::{Component, component_alias}; use springtime_di::instance_provider::ErrorPtr; // Runners execute when application starts #[derive(Component)] struct DatabaseMigrationRunner; #[component_alias] impl ApplicationRunner for DatabaseMigrationRunner { fn run(&self) -> BoxFuture<'_, Result<(), ErrorPtr>> { async { println!("Running database migrations..."); // Migration logic here Ok(()) } .boxed() } // Higher priority runs first fn priority(&self) -> i8 { 10 } } #[derive(Component)] struct ServerStartupRunner; #[component_alias] impl ApplicationRunner for ServerStartupRunner { fn run(&self) -> BoxFuture<'_, Result<(), ErrorPtr>> { async { println!("Starting server..."); // Server startup logic Ok(()) } .boxed() } fn priority(&self) -> i8 { 0 } } #[tokio::main] async fn main() { // Framework discovers all ApplicationRunner implementations let mut application = application::create_default() .expect("Unable to create application"); // Runs all runners in priority order (higher priority first) application.run().await.expect("Error running application"); // Output: // Running database migrations... // Starting server... } ``` ``` -------------------------------- ### Rust: Basic Dependency Injection with Springtime Source: https://context7.com/krojew/springtime/llms.txt Demonstrates basic dependency injection in Rust using the Springtime framework. It shows how to define injectable traits, implement components, and automatically inject dependencies into other components. This requires the `springtime-di` crate. ```rust use springtime_di::{Component, injectable, component_alias}; use springtime_di::factory::ComponentFactoryBuilder; use springtime_di::instance_provider::{ComponentInstancePtr, TypedComponentInstanceProvider}; // Define an injectable trait #[injectable] trait MessageService { fn get_message(&self) -> String; } // Create a component implementing the trait #[derive(Component)] struct HelloWorldService; // Register the implementation as a component alias #[component_alias] impl MessageService for HelloWorldService { fn get_message(&self) -> String { "Hello world!".to_string() } } // Component with injected dependency #[derive(Component)] struct Application { // Automatically injected by the framework service: ComponentInstancePtr, } fn main() { // Create component factory with default configuration let mut factory = ComponentFactoryBuilder::new() .expect("Failed to initialize factory") .build(); // Request component instance - all dependencies resolved automatically let app = factory .primary_instance_typed::() .expect("Failed to create Application"); println!("{}", app.service.get_message()); // Prints: Hello world! } ``` -------------------------------- ### Rust Path Hierarchies and Controller Configuration Source: https://context7.com/krojew/springtime/llms.txt Configures API routes using path prefixes for different controllers, enabling organized and modular endpoint definitions. It demonstrates how to set base paths for controllers and define specific routes within them using annotations. ```rust use axum::extract::Path; use springtime::application; use springtime_di::Component; use springtime_web_axum::controller; // All routes prefixed with /api/v1 #[derive(Component)] struct ApiController; #[controller(path = "/api/v1")] impl ApiController { #[get("/users")] // Full path: GET /api/v1/users async fn list_users(&self) -> &'static str { "User list" } #[get("/users/{id}")] // Full path: GET /api/v1/users/{id} async fn get_user(&self, Path(id): Path) -> String { format!("User {}", id) } } // Admin routes under different prefix #[derive(Component)] struct AdminController; #[controller(path = "/admin")] impl AdminController { #[get("/dashboard")] // Full path: GET /admin/dashboard async fn dashboard(&self) -> &'static str { "Admin dashboard" } #[post("/users/{id}/ban")] // Full path: POST /admin/users/{id}/ban async fn ban_user(&self, Path(id): Path) -> String { format!("Banned user {}", id) } } #[tokio::main] async fn main() { let mut application = application::create_default() .expect("Unable to create application"); // Routes registered: // GET /api/v1/users // GET /api/v1/users/{id} // GET /admin/dashboard // POST /admin/users/{id}/ban application.run().await.expect("Error running application"); } ``` -------------------------------- ### Database Migrations with Refinery (Rust) Source: https://context7.com/krojew/springtime/llms.txt Manages database schema evolution by automatically executing migrations on application startup using Springtime and Refinery. Supports embedding SQL migration files from directories or defining migrations directly in code. Dependencies include `springtime`, `springtime_di`, and `springtime_migrate_refinery`. ```rust use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime_di::{Component, component_alias}; use springtime_di::instance_provider::ErrorPtr; use springtime_migrate_refinery::migration::{embed_migrations, Migration, MigrationSource}; use springtime_migrate_refinery::runner::{MigrationRunnerExecutor, Runner}; use std::sync::Arc; // Embed SQL migration files from directory embed_migrations!("examples/migrations"); // Provide migrations from embedded files #[derive(Component)] struct DatabaseMigrations; #[component_alias] impl MigrationSource for DatabaseMigrations { fn migrations(&self) -> Result, ErrorPtr> { // Use embedded migrations migrations::runner().get_migrations() .map_err(|e| Arc::new(e) as ErrorPtr) } } // Or define migrations in code #[derive(Component)] #[component(names = ["code_migrations"])] struct CodeBasedMigrations; #[component_alias] impl MigrationSource for CodeBasedMigrations { fn migrations(&self) -> Result, ErrorPtr> { let migrations = vec![ Migration::unapplied( "V1__create_users_table", "CREATE TABLE users ( id INTEGER PRIMARY KEY, username TEXT NOT NULL, email TEXT NOT NULL );" )?, Migration::unapplied( "V2__create_posts_table", "CREATE TABLE posts ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, title TEXT NOT NULL, content TEXT, FOREIGN KEY(user_id) REFERENCES users(id) );" )?, ]; Ok(migrations) } } // Execute migrations against database #[derive(Component)] struct SqliteMigrationExecutor { // Inject database connection here } #[component_alias] impl MigrationRunnerExecutor for SqliteMigrationExecutor { fn run_migrations(&self, runner: &Runner) -> BoxFuture<'_, Result<(), ErrorPtr>> { async move { // Execute with rusqlite // let mut conn = Connection::open("app.db")?; // runner.run(&mut conn)?; println!("Migrations executed successfully"); Ok(()) } .boxed() } } #[tokio::main] async fn main() { // Migrations run automatically before other application runners let mut application = application::create_default() .expect("Unable to create application"); application.run().await.expect("Error running application"); } ``` -------------------------------- ### Web Controllers with Axum Integration Source: https://context7.com/krojew/springtime/llms.txt This section describes how to create HTTP endpoints using the controller pattern with automatic routing and dependency injection in Springtime. ```APIDOC ## Web Controllers with Axum Integration Create HTTP endpoints using the controller pattern with automatic routing and dependency injection. Controllers are defined as components and use the `#[controller]` macro to automatically generate Axum handlers from methods. Routing and dependency injection are handled automatically. ### Endpoints #### GET / - **Description**: Returns a plain text string indicating the API version. - **Method**: GET - **Endpoint**: `/` - **Response**: `&'static str` #### GET /{id} - **Description**: Retrieves a user by their ID. Accepts a path parameter for the user ID. - **Method**: GET - **Endpoint**: `/{id}` - **Path Parameters**: - **id** (u64) - Required - The unique identifier of the user. - **Response**: - **Success Response (200)**: - `Json` - Contains the user details. #### POST / - **Description**: Creates a new user. Accepts a JSON request body with user details. - **Method**: POST - **Endpoint**: `/` - **Request Body**: - `Json` - Required - Contains the username and email for the new user. - **Response**: - **Success Response (200)**: - `Json` - Contains the details of the created user. #### GET /search - **Description**: Searches for users based on provided query parameters. - **Method**: GET - **Endpoint**: `/search` - **Query Parameters**: - **(HashMap)** - Optional - A hash map of key-value string pairs representing search criteria. - **Response**: - `String` - A string indicating the search parameters used. ### Example ```rust use axum::extract::{Path, Query}; use axum::Json; use serde::{Deserialize, Serialize}; use springtime::application; use springtime_di::Component; use springtime_web_axum::controller; #[derive(Component)] struct UserController; #[derive(Deserialize)] struct CreateUserRequest { username: String, email: String, } #[derive(Serialize)] struct UserResponse { id: u64, username: String, email: String, } // Controller macro creates Axum handlers from methods #[controller] impl UserController { // GET / returns plain text #[get("/")] async fn index(&self) -> &'static str { "User API v1" } // GET /{id} with path parameter #[get("/{id}")] async fn get_user(&self, Path(id): Path) -> Json { Json(UserResponse { id, username: format!("user{}", id), email: format!("user{}@example.com", id), }) } // POST / with JSON body #[post("/")] async fn create_user(&self, Json(req): Json) -> Json { Json(UserResponse { id: 1, username: req.username, email: req.email, }) } // GET /search with query parameters #[get("/search")] async fn search_users( &self, Query(params): Query> ) -> String { format!("Searching with params: {:?}", params) } } #[tokio::main] async fn main() { let mut application = application::create_default() .expect("Unable to create application"); // Server starts on http://0.0.0.0:8080 by default // Routes automatically registered: // GET / // GET /{id} // POST / // GET /search application.run().await.expect("Error running application"); } ``` ``` -------------------------------- ### Custom Web Server Configuration (Rust) Source: https://context7.com/krojew/springtime/llms.txt Configures custom server addresses and multiple server instances for a web application using Springtime. It allows defining distinct server configurations, including listen addresses, and registering them with the application. Dependencies include `springtime`, `springtime_di`, and `springtime_web_axum`. ```rust use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime_di::{Component, component_alias}; use springtime_di::instance_provider::ErrorPtr; use springtime_web_axum::config::{ ServerConfig, WebConfig, WebConfigProvider, DEFAULT_SERVER_NAME }; use springtime_web_axum::controller; // Custom configuration provider #[derive(Component)] #[component(constructor = "CustomWebConfig::new")] struct CustomWebConfig { #[component(ignore)] config: WebConfig, } impl CustomWebConfig { fn new() -> BoxFuture<'static, Result> { async { let mut web_config = WebConfig::default(); // Configure default server let mut server_config = ServerConfig::default(); server_config.listen_address = "127.0.0.1:3000".to_string(); web_config.servers.insert( DEFAULT_SERVER_NAME.to_string(), server_config ); // Add additional server on different port let mut admin_config = ServerConfig::default(); admin_config.listen_address = "127.0.0.1:9090".to_string(); web_config.servers.insert("admin".to_string(), admin_config); Ok(Self { config: web_config }) } .boxed() } } #[component_alias] impl WebConfigProvider for CustomWebConfig { fn config(&self) -> BoxFuture<'_, Result<&WebConfig, ErrorPtr>> { async { Ok(&self.config) }.boxed() } } #[derive(Component)] struct PublicController; #[controller] // Served on default server (port 3000) impl PublicController { #[get("/")] async fn index(&self) -> &'static str { "Public API" } } #[tokio::main] async fn main() { let mut application = application::create_default() .expect("Unable to create application"); // Server starts on: // http://127.0.0.1:3000 - Default server // http://127.0.0.1:9090 - Admin server application.run().await.expect("Error running application"); } ``` -------------------------------- ### Rust REST API with Springtime and Axum Source: https://context7.com/krojew/springtime/llms.txt Implements a full-featured REST API for product management using Rust, Springtime for dependency injection, and Axum as the web framework. It includes repository, service, and controller layers with CRUD operations and error handling. Dependencies: axum, serde, springtime, springtime-di, springtime-web-axum. ```rust use axum::extract::{Path, Json}; use axum::http::StatusCode; use serde::{Deserialize, Serialize}; use springtime::application; use springtime::future::{BoxFuture, FutureExt}; use springtime_di::{Component, injectable, component_alias}; use springtime_di::instance_provider::{ComponentInstancePtr, ErrorPtr}; use springtime_web_axum::controller; use std::collections::HashMap; use std::sync::{Arc, Mutex}; // Models #[derive(Clone, Serialize, Deserialize)] struct Product { id: u64, name: String, price: f64, stock: u32, } #[derive(Deserialize)] struct CreateProductRequest { name: String, price: f64, stock: u32, } // Repository layer #[injectable] trait ProductRepository: Send + Sync { fn find_all(&self) -> Vec; fn find_by_id(&self, id: u64) -> Option; fn save(&self, product: Product) -> Result; fn delete(&self, id: u64) -> bool; } #[derive(Component)] struct InMemoryProductRepository { products: Mutex>, next_id: Mutex, } #[component_alias] impl ProductRepository for InMemoryProductRepository { fn find_all(&self) -> Vec { self.products.lock().unwrap().values().cloned().collect() } fn find_by_id(&self, id: u64) -> Option { self.products.lock().unwrap().get(&id).cloned() } fn save(&self, mut product: Product) -> Result { if product.id == 0 { let mut next_id = self.next_id.lock().unwrap(); product.id = *next_id; *next_id += 1; } self.products.lock().unwrap().insert(product.id, product.clone()); Ok(product) } fn delete(&self, id: u64) -> bool { self.products.lock().unwrap().remove(&id).is_some() } } // Service layer #[injectable] trait ProductService: Send + Sync { fn list_products(&self) -> Vec; fn get_product(&self, id: u64) -> Option; fn create_product(&self, req: CreateProductRequest) -> Result; fn update_stock(&self, id: u64, stock: u32) -> Result; fn delete_product(&self, id: u64) -> bool; } #[derive(Component)] struct ProductServiceImpl { repository: ComponentInstancePtr, } #[component_alias] impl ProductService for ProductServiceImpl { fn list_products(&self) -> Vec { self.repository.find_all() } fn get_product(&self, id: u64) -> Option { self.repository.find_by_id(id) } fn create_product(&self, req: CreateProductRequest) -> Result { if req.price < 0.0 { return Err("Price cannot be negative".to_string()); } let product = Product { id: 0, name: req.name, price: req.price, stock: req.stock, }; self.repository.save(product) } fn update_stock(&self, id: u64, stock: u32) -> Result { let mut product = self.repository.find_by_id(id) .ok_or_else(|| "Product not found".to_string())?; product.stock = stock; self.repository.save(product) } fn delete_product(&self, id: u64) -> bool { self.repository.delete(id) } } // Controller layer #[derive(Component)] struct ProductController { service: ComponentInstancePtr, } #[controller(path = "/api/products")] impl ProductController { #[get("/")] async fn list(&self) -> Json> { Json(self.service.list_products()) } #[get("/{id}")] async fn get(&self, Path(id): Path) -> Result, StatusCode> { self.service.get_product(id) .map(Json) .ok_or(StatusCode::NOT_FOUND) } #[post("/")] async fn create( &self, Json(req): Json ) -> Result, (StatusCode, String)> { self.service.create_product(req) .map(Json) .map_err(|e| (StatusCode::BAD_REQUEST, e)) } #[put("/{id}/stock/{stock}")] async fn update_stock( &self, Path((id, stock)): Path<(u64, u32)> ) -> Result, (StatusCode, String)> { self.service.update_stock(id, stock) .map(Json) .map_err(|e| (StatusCode::NOT_FOUND, e)) } #[delete("/{id}")] async fn delete(&self, Path(id): Path) -> StatusCode { if self.service.delete_product(id) { StatusCode::NO_CONTENT } else { StatusCode::NOT_FOUND } } } // Initialize with sample data #[derive(Component)] struct DataInitializer { repository: ComponentInstancePtr, } #[component_alias] impl springtime::runner::ApplicationRunner for DataInitializer { } // Example of how to run the application: // #[tokio::main] // async fn main() { // springtime::application::SpringtimeApplication::new() // .run() // .await; // } ``` -------------------------------- ### Run HTTP Server with Springtime Source: https://github.com/krojew/springtime/blob/master/springtime/README.md This Rust code demonstrates basic usage of the Springtime framework to run an HTTP server. It defines an `HttpRunner` component that depends on an `HttpServer` and implements the `ApplicationRunner` trait. The `main` function initializes and runs the Springtime application, which in turn executes the `HttpRunner`. ```rust // the following example shows how to inject an example HTTP server and run it // this is an application runner, which will run when the application starts; the framework will // automatically discover it using dependency injection #[derive(Component)] struct HttpRunner { // let the framework inject the example server http_server: ComponentInstancePtr, } #[component_alias] impl ApplicationRunner for HttpRunner { // note: BoxFuture is only needed when using the "async" feature fn run(&self) -> BoxFuture<'_, Result<(), ErrorPtr>> { // run the example server (run() is assumed to return a Future) self.http_server.run().boxed() } } // note: for the sake of simplicity, errors are unwrapped, rather than gracefully handled #[tokio::main] async fn main() { // create our application, which will detect all runners let mut application = application::create_default().expect("unable to create default application"); // runs all ApplicationRunners, which means our HttpServer application.run().await.expect("error running application"); } ```