Accessing Services — Needs and ~Key

Application effects access services with Needs<K> bounds, caps! in R, and ~Key (or require!) inside effect!.

Single service

#![allow(unused)]
fn main() {
use id_effect::{effect, require, caps, succeed};

fn get_user(id: u64) -> Effect<User, DbError, caps!(UserRepo)> {
    effect!(|r| {
        let repo = ~UserRepo;
        ~ repo.get_user(id)
    })
}
}

Generic over any environment that implements the bound:

#![allow(unused)]
fn main() {
fn get_user<R>(id: u64) -> Effect<User, DbError, R>
where
    R: Needs<UserRepo> + 'static,
{
    effect!(|r: &mut R| {
        let repo = ~UserRepo;
        ~ repo.get_user(id)
    })
}
}

Multiple services

#![allow(unused)]
fn main() {
fn notify_user(id: u64, message: &str) -> Effect<(), AppError, caps!(UserRepo, Email)> {
    effect!(|r| {
        let repo = ~UserRepo;
        let email = ~Email;
        let user = ~ repo.get_user(id).map_error(AppError::Db);
        ~ email.send(&user.email, message).map_error(AppError::Email);
        ()
    })
}
}

Direct Env access

Prefer effect! + ~Config in application code. For small sync helpers outside effect!, Needs::<Config>::need(env) is available.

caps! vs generic R

StyleWhen
Effect<_, _, caps!(K)>Application modules, examples
Effect<_, _, R> where R: Needs<K>Library code that should not fix the env type
Env at HTTP boundariesAxum State<Env>, then run_with_caps

All styles run against the same Env built by run_with or build_env.