query

Attribute Macro query 

Source
#[query]
Expand description

Register a query call entry point.

This attribute macro will export a function with name canister_query <name> in the canister module.

§Examples

§Basic Usage

#[query]
fn query_function() {
    // ...
}

§Custom Export Name

You can customize the name of the exported function.

#[query(name = "some_name")]
fn query_function() {
    // ...
}

§Hide From Candid Generation

If you want to hide this method in the Candid generated by export_candid!, you will need to set hidden to true. The entry point still exists in the canister.

#[query(hidden = true)]
fn query_function() {
    // ...
}

§Guard Functions

You can specify one or more guard functions to be executed before the query function. Each guard function must return a Result<(), String>. If any guard function returns an error, the query function will not proceed.

fn guard1() -> Result<(), String> {
    // ...
}
fn guard2() -> Result<(), String> {
    // ...
}
#[query(guard = "guard1", guard = "guard2")]
fn query_function() {
    // ...
}

§Custom Argument Decoding

You can specify a custom function to decode the arguments. The function must take a Vec<u8> as an argument and return the same type as the query arguments.

fn decode_args(arg_bytes: Vec<u8>) -> (u32, u32) {
   // ...
}
#[query(decode_with = "decode_args")]
fn query_function(a: u32, b: u32) {
   // ...
}

§Custom Return Value Encoding

You can specify a custom function to encode the return value. The function must take the query return value as argument and return a Vec<u8>.

fn encode_result(result: (u32, u32)) -> Vec<u8> {
  // ...
}
#[query(encode_with = "encode_result")]
fn query_function() -> (u32, u32) {
 // ...
}

§Composite Queries

To be able to make inter-canister calls from a query call, it must be a composite query (which cannot be executed in replicated mode).

#[query(composite = true)]
async fn composite_query_function() {
   let (wallet_name,): (Option<String>,) = ic_cdk::call(wallet_canister_principal(), "name", ()).await.unwrap();
}

§Manual Reply

The query macro defaults to invoke msg_reply() after the function execution. If you want to execute other code after msg_reply(), you can:

  • set manual_reply to true in macro attribute;
  • set the return type to PhantomData<T> where T is the return type of the update method;
  • call the msg_reply() function explicitly;
  • do other stuff;
  • return PhantomData;
#[query(manual_reply = true)]
fn query_function() -> PhantomData<MyResult> {
    let result = calculate_result();
    let reply_bytes = candid::encode_one(result).unwrap();
    ic_cdk::api::msg_reply(reply_bytes);
    PhantomData
}