#actix-web #attributes #injection #coi #container #inject #integration

coi-actix-web

coi-actix-web 提供了 coi 与 actix-web 之间的集成支持

9个版本 (破坏性更新)

0.7.1 2023年1月21日
0.6.0 2023年1月16日
0.5.1 2020年9月16日
0.5.0 2020年3月16日

377HTTP服务器

Download history 1/week @ 2024-04-18 11/week @ 2024-07-18 78/week @ 2024-07-25

每月下载量 89

MIT/Apache

19KB
169

coi-actix-web

Build Status docs.rs crates.io

Rust中的依赖注入

此crate为 coiactix-web 版本4提供了集成支持。它暴露了一个 inject 过程式属性宏,用于生成从注册到 actix-webContainer 中检索依赖项的代码。

示例

// What this crate provides
use coi_actix_web::inject;

// What's needed for the example fn below
use actix_web::{get, web, Error, HttpResponse, Responder};
use std::sync::Arc;

// Add the `inject` attribute to the function you want to inject
#[get("/{id}")]
#[coi_actix_web::inject]
async fn get(
    id: web::Path<u64>,
    // Add the `inject` field attribute to each attribute you want
    // injected
    #[inject] service: Arc<dyn IService>
) -> Result<impl Responder, Error> {
    let data = service.get(*id).await?;
    Ok(HttpResponse::Ok().json(DataDto::from(data)))
}

// Just data models for the above fn
use serde::Serialize;

#[derive(Serialize)]
struct DataDto {
    name: String,
}

impl DataDto {
    fn from(data: Data) -> Self {
        Self {
            name: data.name
        }
    }
}


// An example of what's usually needed to make effective use of this
// crate is below
use actix_web::ResponseError;
use coi::Inject;
use futures::future::{ready, BoxFuture};
use futures::FutureExt;

// This section shows coi being put to use
// It's very important that the version of coi and the version
// of coi-actix-web used match since coi-actix-web implements
// some coi traits

#[derive(Debug)]
enum ServiceError {
    Repo(RepoError),
}

impl ResponseError for ServiceError {}

impl From<RepoError> for ServiceError {
    fn from(err: RepoError) -> Self {
        Self::Repo(err)
    }
}

impl std::fmt::Display for ServiceError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            ServiceError::Repo(r) => write!(f, "Repo({})", r),
        }
    }
}

// Here we're marking a trait as injectable
trait IService: Inject {
    fn get(&self, id: u64) -> BoxFuture<Result<Data, ServiceError>>;
}

// And here we're marking a type that's capable of providing the
// above trait
#[derive(Inject)]
#[coi(provides dyn IService with ServiceImpl::new(repo))]
struct ServiceImpl {
    // Here we're injecting a dependency. `ServiceImpl` does
    // not need to know how to get this value.
    #[coi(inject)]
    repo: Arc<dyn IRepo>
}

// Normal impl for struct
impl ServiceImpl {
    fn new(repo: Arc<dyn IRepo>) -> Self {
        Self { repo }
    }
}

// Normal impl of trait for struct
impl IService for ServiceImpl {
    fn get(&self, id: u64) -> BoxFuture<Result<Data, ServiceError>> {
        async move {
            let data = self.repo.read_from_db(id).await?;
            Ok(data)
        }.boxed()
    }
}

// The data that will be passed between services
struct Data {
    id: u64,
    name: String,
}

#[derive(Debug)]
struct RepoError;
impl ResponseError for RepoError {}

impl std::fmt::Display for RepoError {
    fn fmt(&self, f: &mut std::fmt::Formatter)  -> Result<(), std::fmt::Error> {
        write!(f, "RepoError")
    }
}

// Here's the trait from above
trait IRepo: Inject {
    fn read_from_db(&self, id: u64) -> BoxFuture<Result<Data, RepoError>>;
}

// And it's setup below
#[derive(Inject)]
#[coi(provides dyn IRepo with RepoImpl)]
struct RepoImpl;

impl IRepo for RepoImpl {
    fn read_from_db(&self, id: u64) -> BoxFuture<Result<Data, RepoError>> {
        Box::pin(ready(Ok(Data {
            id,
            name: format!("{}'s name...", id)
        })))
    }
}

// This is for the register_container function
use coi_actix_web::AppExt as _;

// Your general server setup in "main". The name here is different
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    use actix_web::{App, HttpServer};
    use coi::container;

    // Construct your coi container with your keys and providers
    // See the coi crate for more details
    let container = container!{
        repo => RepoImplProvider; scoped,
        service => ServiceImplProvider; scoped
    };

    HttpServer::new(move || {
        App::new()
        // Don't forget to register the container or else
        // the injections will fail on every request!
        .register_container(container.clone())
        .service(get)
    })
    .bind("127.0.0.1:8000")?
    .run()
    .await
}

请参阅仓库 coi-actix-sample 以获取更复杂的示例。

许可协议

根据您的选择,在以下两者中许可:[Apache License, Version 2.0](https://github.com/nashenas88/coi-actix-web/blob/8fecd7b4b403ca378ba84ad9d964ba379bf13c71/LICENSE.Apache-2.0) 或 [MIT license](https://github.com/nashenas88/coi-actix-web/blob/8fecd7b4b403ca378ba84ad9d964ba379bf13c71/LICENSE.MIT)。
除非您明确声明,否则任何有意提交以包含在此crate中的贡献,根据Apache-2.0许可协议定义,应如上双许可,不附加任何额外条款或条件。

SPDX-许可协议-标识符: MIT Apache-2.0

依赖项

~14–26MB
~455K SLoC