Calling public functions not in main.mo with "dfx canister call"

I’ve been using “dfx canister call” to test my backend motoko functions and it has worked pretty well so far. Recently I’ve refactored my code so that more of the logic is split across multiple files, which are imported in the main.mo file. Eg import App “./App”;

Can i call the public functions in the same canister that are not in main.mo? or do i have to wrap methods in my main.mo?

I couldn’t find anything on how to do this in the below documentation.

You’re splitting your code into modules like that (which is good practice) and modules are only exposed internally in the project. The main.mo file contains the actor with your public facing interface, which is the sole entry point to the deployed canister.

If you look in your project’s dfx.json you’ll see a canister entry that points to this main.mo file. (There’s also an asset canister in there which serves your deployed frontend).

A single project can contain multiple canisters, you’d just add an entry in dfx.json and the corresponding files (usually in a new directory alongside main.mo’s). But note that calls between these canisters will be made with the same behaviour as calls to any canister on the network, so asynchronous, and currently inter-canister calls are update only (no query calls).

I’d expect many projects will be multi-canister as things progress with the network. It just depends on what setup is most suitable for your project.

Thanks @Ori,
Yeah i looked into creating multiple canisters, and how the dfx.json file would look with that setup.
However because of the current limitations of multi cannister models, i dont think i want to do that yet.

I was hoping i could change the dfx.json file to something like this:
“canisters”: {
“testproject1”: {
“main”: “src/testproject1/main.mo”,
“App”: “src/testproject1/App.mo”,
“type”: “motoko”
},

Or call App.functionFromApp() in the command line.

If i cannot do either of those approaches, i think i will move methods i had in App to other modules, and always call from main.mo.

I just wanted to check if that was a reasonable approach, or if i was missing something obvious.

Thanks for your help.

No prob, no not missing anything obvious I don’t think, App.functionFromApp() would have to be a public method in its own canister to call it externally.

The use of modules is an implementation detail of the actor you are building. The interface of the canister is defined solely by the public methods of the actor. If there is additional functionality you want to expose, you have to add appropriate methods to the actor.

PS, an aside: you never need to import a module file as "./App", simply writing "App" as URL is sufficient – Motoko interprets URLs with the correct semantics for relative paths, which means that both of these are equivalent and a ./ prefix is always redundant.

(This may be in contrast to some other eco-systems, e.g. ones revolving around JavaScript, which have bastardised the URL/URI specification and treat relative paths incorrectly.)

1 Like