0

I know Dependency Injection and OO is not super popular with Rust but coming from Go I want to be able to mock and test a web server across the "typical" 3 layers stack (controller, service, repository).

I managed to achieve dependency injection so:

#[automock]
pub trait Repository {
    fn save_into_db(item: Item) -> Result<(), Error>
}

#[derive(Clone)]
pub struct Service {
    repository: Arc<dyn Repository>
}

impl Service {
    fn new(repository: Arc<dyn Repository>) -> Self {
        Self {
            repository
        }
    }
}

However when I try to inject the dynamoDB Client as provided by AWS SDK Rust (https://docs.aws.amazon.com/sdk-for-rust/latest/dg/rust_dynamodb_code_examples.html) and construct the Repository, I can't pass the Client object that implement the sdk methods as a trait to the repository constructor as I would normally do in Go.

#[automock]
pub trait IDynamo: Send + Sync {
    fn put_item(&self) -> PutItem;
    fn query(&self) -> Query;
}

#[derive(Clone)]
pub struct Repository {
    pub dynamo: Arc<dyn IDynamo>,
}

impl Repository {
    pub fn new(dynamo: Arc<dyn IDynamo>) -> Self {
        Self {
            dynamo
        }
    }
}

...
async fn main() -> std::io::Result<()> {
    ...
    let repository = Repository::new(client) <- this errors
    ...

mismatched types expected struct Arc<(dyn IDynamo + 'static)>
found struct aws_sdk_dynamodb::Client

The error is clear but this would normally succeed in Go because the struct implements the interface.

What is the Rusty way to achieve the same behaviour? I am also open to hear other non OO ways that may be more suited for Rust as long as they can achieve the same test coverage.

Thanks

matthausen
  • 39
  • 8
  • 1
    This wouldn't succeed in Go either, because on the surface, you're just passing in a wrong concrete type, traits aren't at play yet. `new` expects an `Arc` but gets a `Client`. If you instead did `Repository::new(Arc::new(client))` you'll be fine. It should do the cast to `Arc` implicitly. By the way, prefixing traits with `I` is an anti-pattern in Rust. – isaactfa Aug 15 '22 at 08:46
  • 1
    The idea is sound (use trait objects for dependency injection is a standard pattern), but I agree with isaactfa that the execution was the failing point. The linked Q&A should get you on the right path with applying the idea to Actix-web. – kmdreko Sep 20 '22 at 18:29

0 Answers0