Generic ICC (Intercanister Call) type

hello,

I am working on an “integration” project and one of the features is that the user choose what canister, method and args to pass into the backend, and the backend will make an intercanister call based on these input:

let response: Result<(String,), (RejectionCode, String)> = call::call(
  data.canister,
  &data.method,
  (id,)
).await;

the issue here is that the return value of the ICC is not known to me since its not something I can know because it can be any canister and method specified by the user.

is there a way to use a generic type for the return value of the ICC? I tried using serde_json’s Value but thats giving me an error

the trait bound `Value: CandidType` is not satisfied
the following other types implement trait `CandidType`:
  bool
  isize
  i8
  i16
  i32
  i64
  i128
  usize
and 139 others
required for `(Value,)` to implement `for<'a> ArgumentDecoder<'a>`

also dont think Value of a good choice here, since it woud be a Result, Option etc…

so when I execute this call it returns an error: failed to decode canister response as (alloc::string::String,): Fail to decode argument 0 from table0 to text.

2 Likes

Haven’t tried it myself, but candid’s blob sounds most appropriate. In Rust that would be Vec<u8>

would that mean I need to send back a Vec<u8> to the front end? What I actually want as the next step is to send back the response as a “preview” response back to the front end and show the response

You can send a response blob to the frontend and decode it in the frontend (and show as preview).

thats what I have been trying, sending back the Vec<u8> to the front end and decode it, but without success. Also, I need the Vec<u8> to be “real” data futher along in the process. I looked into the decode_args from candid but that required a tuple type which I dont have

So the flow is:

  • receive data
  • fetch data from another canister (canisterId etc supplied by user)
  • use the fetched data futher in the process, add, combine data with other flows

So I digged in a bit deeper and afaik the only way actually doing it is by using the call_raw call

  1. encoding the args with encode_args, returns Vec<u8>
  2. passing the encoded args to call_raw, return Result<Vec<u8>, ...>
  3. return Vec<u8> to the front end and decode (how? I’ve tried some stuff but didnt work)
  4. decode Vec<u8> in the backend so that the rest of the flows step can actually use the data in the next steps

so im stuck with 3 and 4