tideway 0.7.17

A batteries-included Rust web framework built on Axum for building SaaS applications quickly
Documentation
# Dependency Injection with AppContext

Tideway's `AppContext` provides dependency injection for database pools, cache, and session stores.

## AppContext Structure

`AppContext` holds optional references to your application dependencies. Use helper methods for cleaner access:

```rust
use tideway::AppContext;

// Access dependencies with error handling
match context.database() {
    Ok(db) => {
        // Use database - returns error if not configured
    }
    Err(_) => {
        // Database not configured
    }
}

// Or use optional access
if let Some(cache) = context.cache_opt() {
    // Use cache - returns None if not configured
}

// Required dependency pattern
let sessions = context.sessions()?;  // Returns error if not configured
```

## Builder Pattern

Use the builder to construct your context:

```rust
use tideway::{AppContext, SeaOrmPool, InMemoryCache, InMemorySessionStore};
use std::sync::Arc;

let db_pool = Arc::new(SeaOrmPool::from_config(&db_config).await?);
let cache = Arc::new(InMemoryCache::new(10000));
let sessions = Arc::new(InMemorySessionStore::new(Duration::from_secs(3600)));

let context = AppContext::builder()
    .with_database(db_pool)
    .with_cache(cache)
    .with_sessions(sessions)
    .build();
```

## Using with Axum

Make `AppContext` available to your handlers via Axum's `State`:

```rust
use axum::{extract::State, Json};
use tideway::AppContext;

async fn my_handler(State(context): State<AppContext>) -> Json<Response> {
    // Use helper methods for cleaner access
    if let Ok(cache) = context.cache() {
        // Use cache - returns error if not configured
    }

    // Or use optional access
    if let Some(cache) = context.cache_opt() {
        // Use cache - returns None if not configured
    }

    Json(Response { /* ... */ })
}

// In your router setup:
let app = Router::new()
    .route("/api/endpoint", get(my_handler))
    .with_state(context);
```

## Dependency Patterns

### Pattern 1: Optional Dependencies

Handle missing dependencies gracefully:

```rust
async fn handler(State(ctx): State<AppContext>) -> Result<Response> {
    // Use optional access for graceful fallback
    let result = if let Some(cache) = ctx.cache_opt() {
        cache.get("key").await?
    } else {
        None
    };

    // Fallback logic when cache is unavailable
    Ok(Response { /* ... */ })
}
```

### Pattern 2: Required Dependencies

Assert dependencies exist:

```rust
async fn handler(State(ctx): State<AppContext>) -> Result<Response> {
    // Use helper method - returns error if not configured
    let db = ctx.database()?;

    // Use database
    Ok(Response { /* ... */ })
}
```

## Testing

Create test contexts with mock implementations:

```rust
use tideway::{AppContext, NoOpCache};

let test_context = AppContext::builder()
    .with_cache(Arc::new(NoOpCache))
    .build();
```