How to
As discussed in What is Candid?, Candid provides a language-agnostic way to interact with canisters. By using Candid, you can specify input argument values and display return values from canister methods regardless of whether you interact with the IC from a terminal using the dfx
command-line interface, through a web browser, or from a program written in JavaScript, Motoko, Rust, or any other language. Now that you are familiar with what Candid is and how it works, this section provides instructions for how to use it in some common scenarios.
As a concrete example, let’s assume there is a counter
canister already deployed on the network with the following Candid interface:
service Counter : {
inc : (step: nat) -> (nat);
}
Now, let’s explore how to interact with this canister in different scenarios with the help of Candid.
The .did file
Candid types can be used to describe a service via a Candid service description file (.did
file), which can either be manually written or generated from a service implementation.
If you write a canister in Motoko, for example, the compiler automatically generates a Candid description when you compile the program. If you use the SDK, you will typically see the auto-generated .did
files in the /declarations
directory of your project. Since these files are are auto-generated, it is recommended they should not be manually edited. Even if you change the .did
files in your project, they will be overwritten in the next dfx build.
In other languages, like Rust, you will have to write the Candid interface description manually. With the help of types, we developed tools to automatically generate UI and perform random testing based on the service description file.
Interact with a service in a terminal
One of the most common ways you interact with canisters and the IC is by using the DFINITY Canister SDK dfx
command-line interface.
The dfx
tool provides the dfx canister call
command to call a specific deployed canister—essentially a smart contract that runs on the IC—and, if applicable, a method of the service provided by the smart contract.
When you run the dfx canister call
command, you can pass arguments to a method by specifying them as Candid textual values.
When you pass Candid textual values on the command-line, you can specify multiple argument values separated by commas (,
) and wrapped inside parentheses. For example, specifying (42, true)
represents two argument values, where the first argument is the number 42
and the second argument is a boolean value of true
.
The following example illustrates using the dfx canister call
command to call the counter
canister service and pass arguments for the inc
method:
$ dfx canister call counter inc '(42)'
(43)
To figure out how to create more complex Candid arguments, please refer to the Candid Reference. And for Candid arguments too long to fit the command line, please use the --argument-file
flag of dfx canister call
.
You can also omit the arguments and let dfx
generate a random value that matches the method type. For example:
$ dfx canister call counter inc
Unspecified argument, sending the following random argument:
(1_543_454_453)
(1_543_454_454)
For more information about using dfx
and the dfx canister call
command, see Command-line reference and dfx canister documentation.
Interact with a service from a browser
The Candid interface description language provides a common language for specifying the signature of a canister. Based on the type signature of the service offered by the smart contract, Candid provides a web interface—the Candid UI—that allows you to call canister functions for testing and debugging from a web browser without writing any frontend code.
To use the Candid web interface to test the `counter `canister:
Find the Candid UI canister identifier associated with the
counter
canister using thedfx canister id __Candid_UI
command.dfx canister id __Candid_UI
The command displays the canister identifier for the Candid UI with output similar to the following:
r7inp-6aaaa-aaaaa-aaabq-cai
Start the canister execution environment locally by running the following command:
dfx start --background
Open a browser and navigate to the address and port number specified in the
dfx.json
configuration file.By default, the
local
canister execution environment binds to the127.0.0.1:8000
address and port number.Add the required
canisterId
parameter and the Candid UI canister identifier returned by thedfx canister id
command.For example, the full URL should look similar to the following but with the
CANDID-UI-CANISTER-IDENTIFIER
that was returned by thedfx canister id
command:http://127.0.0.1:8000/?canisterId=<CANDID-UI-CANISTER-IDENTIFIER>
The browser displays a form for you to specify a canister identifier or choose a Candid description (
.did
) file.If you aren’t sure which canister identifier to use, you can run the
dfx canister id
command to look up the identifier for a specific canister name.For example, if you want to view the functions for the
counter
service description, you could look up the canister identifier by running the following command:dfx canister id counter
Specify a canister identifier or description file, then click Go to display the service description.
Review the list of function calls and types defined in the program.
Type a value of the appropriate type for a function or click Random to generate a value, then click Call or Query to see the result.
For more information about the tool that creates a Web interface from the Candid interface of any canister, see the Candid UI repository.
Interact with a service from a Motoko canister
If you are writing a canister in Motoko, the Motoko compiler automatically translates the signature of your canister’s top-level actor
or actor class
into a Candid description, and the dfx build
command ensures that the service description is properly referenced where it needs to be.
For example, if you want to write a hello
canister that calls the counter
canister in Motoko:
import Counter "canister:Counter";
import Nat "mo:base/Nat";
actor {
public func greet() : async Text {
let result = await Counter.inc(1);
"The current counter is " # Nat.toText(result)
};
}
In this example, when the import dependency on the counter
canister— the import Counter "canister:Counter"
declaration—is processed by the dfx build
command, the dfx build
command ensures that the counter
canister identifier and the Candid description are passed to the Motoko compiler correctly. The Motoko compiler then translates the Candid type into the appropriate native Motoko type. This translation enables you to call the inc
method natively—as if it were a Motoko function—even if the counter
canister is implemented in a different language and even if you do not have the source code for the imported canister. For additional information on the type mapping between Candid and Motoko, you can consult the Supported types reference section.
The Motoko compiler and dfx build
command also auto-generate the Candid description for the hello
canister to allow other canisters or tools to interact with the hello
canister seamlessly. The generated Candid description is located in your project build directory at .dfx/local/canisters/hello/hello.did
.
Interact with a service from a Rust canister
If you write a canister in Rust, the dfx build
command ensures that the service description is properly referenced where it needs to be. However, you need to write the Candid service description manually following the conventions described in the Candid specification.
For example, if you want to write a hello
canister that calls the counter
canister in Rust:
use ic_cdk_macros::*;
#[import(canister = "counter")]
struct Counter;
#[update]
async fn greet() -> String {
let result = Counter::inc(1.into()).await;
format!("The current counter is {}", result)
}
When the import macro on the counter
canister— the #[import(canister = "counter")]
declaration—is processed by the dfx build
command, the dfx build
command ensures that the counter
canister identifier and the Candid description are passed to the Rust CDK correctly. The Rust CDK then translates the Candid type into the appropriate native Rust type. This translation enables you to call the inc
method natively—as if it were a Rust function—even if the counter
canister is implemented in a different language and even if you do not have the source code for the imported canister. For additional information on the type mapping between Candid and Rust, you can consult the Supported types reference section.
For other canisters and tools to interact with the hello
canister, you need to manually create a .did
file:
service : {
greet : () -> (text);
}
There is also an experimental feature to generate a Candid service description automatically, see this test case as an example.
For additional information and libraries to help you create Candid services or canisters in Rust, see the documentation for the Candid crate, Rust CDK examples and the Rust tutorials.
Interact with a service from JavaScript
The dfinity/agent npm package includes support for importing canisters using Candid.
For example, if you want to call the counter
canister, you can write the following JavaScript program:
import counter from 'ic:canisters/counter';
import BigNumber from 'bignumber.js';
(async () => {
const result = await counter.inc(new BigNumber(42));
console.log("The current counter is " + result.toString());
})();
When the import dependency of counter canister is processed by the dfx build
command and the webpack
configuration, this processing ensures that the canister identifier and the Candid description are passed to the JavaScript program correctly. Behind the scenes, the Candid service description is translated into a JavaScript module, located at .dfx/local/canister/counter/counter.did.js
, by dfx build
. The dfinity/agent
package then translates the Candid type into native JavaScript values and enables you to call the inc
method natively—as if it were a JavaScript function—even if the counter
canister is implemented in a different language and even if you do not have the source code for the imported canister. For additional information on the type mapping between Candid and JavaScript, you can consult the Supported types reference section.
Create a new Candid implementation
In addition to the Candid implementations for Motoko, Rust, and JavaScript, there are community-supported Candid libraries for the following host languages:
If you want to create a Candid implementation to support a language or tool for which an implementation is not currently available, you should consult the Candid specification.
If you add a Candid implementation for a new language or tool, you can use the official Candid test data to test and verify that your implementation is compatible with Candid, even in slightly more obscure corner cases.