[][src]Crate coi_actix_web

This crate provides a simple Dependency Injection framework for actix-web.

Example

In Cargo.toml:

[dependencies]
coi = { package = "coi-actix-web", version = "0.4.0" }
actix-web = "2.0.0"

Note that the following example is heavily minified. Files names don't really matter. For a more involved example, please see the coi-actix-sample repository.

In your main binary:

This example is not tested
use crate::infrastructure::{RepositoryProvider, PoolProvider};
use crate::service::ServiceProvider;
use coi::container;
use actix_web::{App, HttpServer};
 
mod traits;
mod infrastructure;
mod routes;
mod service;
 
fn main() {
    // container! only expects identifiers, so construct this provider outside
    let postgres_pool = PoolProvider::<NoTls>::new(/* construct actual pool */);
 
    // Build your container
    let container = container! {
        pool => postgres_pool.singleton,
        service => ServiceProvider.scoped,
        repository => RepositoryProvider.scoped,
    };

    HttpServer::new(move || {
        App::new()
             // Make sure to assign it to `app_data` and not `data`
            .app_data(container.clone())
            .configure(routes::data::route_config)
    })
    ...
}

traits.rs:

This example is not tested
use coi::Inject;
 
// Ensure all of your traits inherit from `Inject`
pub trait IService: Inject {
    ...
}
 
pub trait IRepository: Inject {
    ...
}

service.rs

This example is not tested
use crate::traits::IService;
use coi::Inject;
use std::sync::Arc;
 
// derive `Inject` for all structs that will provide the injectable traits.
#[derive(Inject)]
#[provides(pub dyn IService with Service::new(repository))]
struct Service {
    #[inject]
    repository: Arc<dyn IRepository>,
}
 
impl IService for Service {
    ...
}

Note: See coi::Inject for more examples on how to use #[derive(Inject)]

infrastructure.rs

This example is not tested
use crate::traits::IRepository;
use coi::Inject;
use ...::PostgresPool;
#[cfg(feature = "notls")]
use ...::NoTls;
#[cfg(not(feature = "notls"))]
use ...::Tls;
 
#[derive(Inject)]
#[provides(pub dyn IRepository with Repository::new(pool))]
struct Repository {
    #[cfg(feature = "notls")]
    #[inject]
    pool: PostgresPool<NoTls>,

    #[cfg(not(feature = "notls"))]
    #[inject]
    pool: PostgresPool<Tls>,
}
 
impl IRepository for Repository {
    ...
}
 
#[derive(Inject)]
struct Pool<T> where T: ... {
    pool: PostgresPool<T>
}
 
#[derive(Provide)]
#[provides(pub Pool<T> with Pool::new(self.0.pool))]
struct PoolProvider<T> where T: ... {
    pool: PostgresPool<T>
}
 
impl<T> PoolProvider<T> where T: ... {
    fn new(PostgresPool<T>) -> Self { ... }
}

routes.rs

This example is not tested
use crate::service::IService;
use actix_web::{
    web::{self, HttpResponse, ServiceConfig},
    Responder,
};
use coi::inject;
use std::sync::Arc;
 
#[inject]
async fn get(
    id: web::Path<i64>,
    #[inject] service: Arc<dyn IService>,
) -> Result<impl Responder, ()> {
    let name: String = service.get(*id).await.map_err(|e| log::error!("{}", e))?;
    Ok(HttpResponse::Ok().json(name))
}
 
#[inject]
async fn get_all(#[inject] service: Arc<dyn IService>) -> Result<impl Responder, ()> {
    let data: Vec<String> = service.get_all().await.map_err(|e| log::error!("{}", e))?;
    Ok(HttpResponse::Ok().json(data))
}
 
pub fn route_config(config: &mut ServiceConfig) {
    config.service(
        web::scope("/data")
            .route("", web::get().to(get_all))
            .route("/", web::get().to(get_all))
            .route("/{id}", web::get().to(get)),
    );
}

Macros

container

A macro to simplify building of Containers.

Structs

Container

A struct that manages all injected types.

ContainerBuilder

A builder used to construct a Container.

Registration

Enums

Error

Errors produced by this crate

RegistrationKind

Control when Container will call Provide::provide.

Traits

Inject

A marker trait for injectable traits and structs.

Provide

A trait to manage the construction of an injectable trait or struct.

Type Definitions

Result

Type alias to Result<T, coi::Error>.

Attribute Macros

inject

The #[inject] proc macro should only be applied to functions that will be passed to actix-web's routing APIs.

Derive Macros

Inject

Generates an impl for Inject and also generates a "Provider" struct with its own Provide impl.

Provide

There might be some cases where you need to have data passed in with your provider.