0

I have many lib crates and only one bin crate.

In the lib crates I have this simple code (different for each one):

use async_graphql::{Context, Object, Result};
use app::Services;
use std::sync::Arc;

#[derive(Default)]
pub struct PlayersQueryRoot;

#[Object]
impl PlayersQueryRoot {
    async fn players_query_root(&self, ctx: &Context<'_>) -> Result<String> {
        let res = ctx.data_unchecked::<Arc<Services>>(); // Services here is declared in `app` and imported with Cargo.toml, hence the issue

        let player = res.player_by_id.handle(1).await?;

        Ok(player.name)
    }
}

In the bin crate (called app) I have this code:

use async_graphql::{EmptyMutation, EmptySubscription, Schema};
use graphql::{GraphqlSchema, QueryRoot};
use std::sync::Arc;

pub struct Services {
    pub players: Arc<players::Service>,
    pub user: Arc<user::Service>,
}

impl Services {
    pub async fn new() -> Self {
        Self {
            user: Arc::new(user::new(/*some needed injection*/)),
            players: Arc::new(players::new(/*some needed injection*/)),
        }
    }
}

//...

pub fn create_schema(services: Arc<Services>) -> GraphqlSchema {
    Schema::build(QueryRoot::default(), EmptyMutation, EmptySubscription)
        .data(services)
        .finish()
}

It doesn't work because there is a cyclic dependency between app (bin crate) which has the lib crates as dependencies:

[dependencies]
players = { path = "../crates/players" }
users = { path = "../crates/users" }

Is there a way to fix this?

Fred Hors
  • 3,258
  • 3
  • 25
  • 71
  • Your library crate should not depend on your binary crate. – kmdreko Sep 22 '22 at 18:19
  • Yeah. I know. But even if I create another crate for Services constructor the problem is the same, right? – Fred Hors Sep 22 '22 at 18:19
  • Why do you have so many crates? And yes, you'll obviously have a problem if your crates defining `Player`/`User` also require `Services` to function but that is defined in a crate that requires definitions of `Player`/`User`. You can probably keep your structure if you store each `player/user::Service` on the `Context` separately instead of with a meta `Services` type. – kmdreko Sep 22 '22 at 18:34
  • 1
    Are you sure you want a *crate* for every one of those types and not a *mod*? A create is meant to provide a complete package of some sort, and be publishable. Do you think it would make sense to publish only the `Player` crate without the other ones? If no, you should combine them to a single crate. Your crate can have a library and a binary, not even that requires two crates. – Finomnis Sep 22 '22 at 19:05
  • I need many crates because they are exportable using the DDD definition. They are interchangeable and root aggregates. Do you think there is another way to do this? – Fred Hors Sep 22 '22 at 20:32
  • You should not have GraphQL logic in your player/user crates if you're following domain-driven-design. That is strictly part of the API layer, not the domain. See [Why the domain model should not be used as resources in REST API?](/q/33970716/2189130) – kmdreko Sep 22 '22 at 20:50

0 Answers0