Export candid from crate used by consumer

I’m trying to consume exported functions that are using the cdk macros from a crate (lib) into a consumer. This works great.

However, I’m not able to use export_candid in the latest (the consumer) to generate automatically the did files. Is there a way to do so?

Lib crate:

use ic_cdk::{query};

#[query]
pub fn hello() -> String {
    "world".to_string()
}

#[macro_export]
macro_rules! include_lib {
    () => {
        use lib::{hello};
    };
}

Consumer:

use ic_cdk::{export_candid};
use lib::include_lib;

include_lib!();

export_candid!();

When I generate the did file, I get service : {}.

1 Like

For such lib/canister separated structure, it’s better to not “registering” endpoints in the lib crate, i.e. no #[query] in the lib.

For your example, I would modify it into:

Lib crate:

use ic_cdk::{query};

// <--- no #[query] here
pub fn hello() -> String {
    "world".to_string()
}

Consumer:

use ic_cdk::{export_candid};

#[query]
pub fn hello() -> String {
    lib::hello()
}

export_candid!();
2 Likes

Curious why it’s better?

Unless there is a solid reason, I want to register endpoints in the lib crate, that’s my goal.

1 Like

IMO, it should be the canister bin crate to decide which set of endpoints should be registered. If an endpoint was registered in the lib crate, the canister bin crate won’t be able to get rid of it.

In your original example code, even if there is no include_lib!(); line in the consumer, the compiled wasm will have the hello query endpoint. Any crate depends on the lib (just having it in Cargo.toml dependencies) will silently register the endpoint.
Some other consumers may want to register their own hello endpoint, which will end in a name conflict.

By saying “better”, I just want to express that the structure will be more intuitive and less error-prone.

I want to register endpoints in the lib crate, that’s my goal.

IMO, a crate which registers endpoints is not a lib. It sounds more like registering endpoints in different components and gluing them together into one canister wasm.

As I just used the word “components”, the “wasm components model” might be the real solution for this level of code reusing. I imagine that we will be able to have a canister wasm consists of several components implemented in different languages/CDKs. Unfortunately, we don’t have the support for “components model” in IC wasm runtime yet.

1 Like

That’s indeed my goal. I can understand your perspective, it’s due to the fact that you don’t have the full scope. I should have use another word than “lib” maybe too.

So to answer my original question, the answer is: no, it’s not possible to generate the did files the way I want to.

1 Like