Passing arguments in a terminal

This tutorial provides a simple variation on the default program that lets you pass a single string argument to a single actor (object), compile the code to create a canister, then retrieve the argument.

This tutorial illustrates the options to explicitly specify the argument type and how to have the argument type inferred using the interface description language (IDL). The tutorial also illustrates how you could modify the program to allow it to accept more than one value for the string argument.

Before you begin

  • You have downloaded and installed the SDK as described in Getting started.

  • You have stopped any network replica processes running on the local computer.

This tutorial takes approximately 20 minutes to complete.

Create a new project

To create a new project for this tutorial:

  1. Open a terminal shell on your local computer, if you don’t already have one open.

  2. Change to the folder you are using for your Internet Computer sample projects.

  3. Create a new project by running the following command:

    dfx new hello_location
  4. Change to your project directory by running the following command:

    cd hello_location

Verify the default configuration

You have already seen that creating a new project adds a default dfx.json configuration file to your project directory. Review the default settings in the file to verify the file and directory names reflect the names you want to use.

To verify settings in the default dfx.json configuration file:

  1. Open the dfx.json configuration file in a text editor.

  2. Check the default settings for the hello_location project.

    {
      "canisters": {
        "hello_location": {
          "frontend": {
            "entrypoint": "src/hello_location/public/index.js"
          },
          "main": "src/hello_location/main.mo"
        }
      },
      "defaults": {
        "build": {
          "output": "canisters/"
        },
        "start": {
          "address": "127.0.0.1",
          "port": 8000,
          "serve_root": "canisters/hello_location/assets"
        }
      }
    }
  3. Close the file to continue.

Modify the default template program

You have already seen that creating a new project creates a default src directory with a template main.mo file.

To modify the default template source code:

  1. Open the src/hello_location/main.mo source code file in a text editor.

  2. Modify the default source code to replace the greet function with a location function and the name argument with a city argument.

    For example:

    actor {
        public func location(city : Text) : async Text {
            return "Hello, " # city # "!";
        };
    };
  3. Save your changes and close the file to continue.

Build and deploy the program

You now have a program that you can compile into an executable WebAssembly module that you can deploy—using the canister model—on your local replica network.

To build the program executable:

  1. Build the WebAssembly executable by running the following command:

    dfx build
  2. Start the Internet Computer network on your local computer by running the following command:

    dfx start --background
  3. Deploy your hello_location project on the local network by running the following command:

    dfx canister install hello_location

    The command displays output similar to the following:

    Installing code for canister hello_location, with canister_id ic:E75C3765B661880C3E

Pass a string argument to the canister

You now have a program deployed as a canister on your local replica network and can test your program by using dfx canister call commands.

To test the program you have deployed on the local replica network:

  1. Call the location method in the program and pass your city argument of type string by running the following command:

    dfx canister call hello_location location "San Francisco" --type string

    In this example, you are explicitly identifying your argument data type as a string. The command displays output similar to the following:

    ("Hello, San Francisco!")
  2. Call the location method in the program and pass your city argument without specifying a type to have the interface description language infer the type automatically by running the following command:

    dfx canister call hello_location location '("Paris")'

    The command displays output similar to the following:

    ("Hello, Paris!")
  3. Rerun the dfx canister call command using San Francisco as the city argument without specifying a type to have the interface description language infer the type automatically by running the following command:

    dfx canister call hello_location location '("San Francisco")'

    The command displays output similar to the following:

    ("Hello, San Francisco!")

    Because your program only accepts a single string argument, specifying multiple strings only returns the first argument.

    For example, if you run the following command:

    dfx canister call hello_location location '("San Francisco","Paris","Rome")'

    Only the first argument is returned:

    ("Hello, San Francisco!")

Revise the source code in your program

To extend what you have learned in this tutorial, you might want to try modifying the source code to return different results. For example, you might want to modify the location function to return multiple city names.

To experiment with modifying the source code for this tutorial:

  1. Open the dfx.json configuration file in a text editor and change the default hello_location settings to favorite-cities. For example:

    {
      "canisters": {
        "favorite-cities": {
          "frontend": {
            "entrypoint": "src/favorite-cities/public/index.js"
          },
          "main": "src/favorite-cities/main.mo"
        }
      },
      "defaults": {
        "build": {
          "output": "canisters/"
        },
        "start": {
          "address": "127.0.0.1",
          "port": 8000,
          "serve_root": "canisters/favorite-cities/assets"
        }
      }
    }
  2. Copy the hello_location source file directory to match the name specified in the dfx.json configuration file by running the following command

    cp -r src/hello_location src/favorite-cities
  3. Open the src/favorite-cities/main.mo file in a text editor.

  4. Copy and paste the following code sample to replace the location function with two new functions.

    For example:

    actor {
        public func location(cities : [Text]) : async Text {
            return "Hello, from " # (debug_show cities) # "!";
        };
        public func location_pretty(cities : [Text]) : async Text {
            var str = "Hello from ";
            for (city in cities.vals()) {
                    str := str # city #", ";
            };
            return str # "bon voyage!";
        }
    };

    You might notice that Text in this code example is enclosed by square ([ ]) brackets. By itself, Text represents a collection of UTF-8 characters. The square brackets around a type indicate that it is an array of that type. In this context, therefore, the [Text] indicates an array of a collection of UTF-8 characters, enabling the program to accept and return multiple text strings.

    The code sample also uses the basic format of an apply operation for the array, which can be abstracted as:

    public func apply<A, B>(fs : [A -> B], xs : [A]) : [B] {
        var ys : [B] = [];
        for (f in fs.vals()) {
          ys := append<B>(ys, map<A, B>(f, xs));
        };
        ys;
    };

    For information about the functions that perform operations on arrays, see the description of the standard library array.mo in the Motoko Programming Language Reference.

  5. Build the WebAssembly executable by running the following command:

    dfx build --skip-frontend

    For this tutorial, you can build using the --skip-frontend because you aren’t changing the default front-end for the new program. If you also wanted to update the front-end, you would open the default src/favorite-cities/public/index.js file to change the canister name and make other changes.

  6. Deploy your favorite-cities program on the local network by running the following command:

    dfx canister install favorite-cities
  7. Call the location method in the program and pass your city argument using the interface description syntax by running the following command:

    dfx canister call favorite-cities location '(vec {"San Francisco";"Paris";"Rome"})'

    The command uses the interface description syntax (vec { val1; val2; val3; }) to return vector of values. For more information about the interface description syntax, see Interface description syntax for arguments.

    This command displays output similar to the following:

    ("Hello, from [\"San Francisco\", \"Paris\", \"Rome\"]!")
  8. Call the location_pretty method in the program and pass your city argument using the interface description syntax by running the following command:

    dfx canister call favorite-cities location_pretty '(vec {"San Francisco";"Paris";"Rome"})'

    The command displays output similar to the following:

    ("Hello from San Francisco, Paris, Rome, bon voyage!")

Testing functions in a browser

The canister interface description language—often referred to as Candid or more generally as the IDL—provides a common language for specifying the signature of a canister service. The language provides a unified way of interacting with canisters in various languages and tools, such as the dfx command-line interface, JavaScript, and Motoko.

Based on the type signature of the actor, Candid provides a web interface that allows you to call canister functions for testing and debugging.

To use the Candid web interface to test canister functions:

  1. Deploy your project using the dfx canister install command and copy the canister identifier that begins with the ic: prefix.

  2. Open a browser and navigate to the address and port number specified in the dfx.json configuration file.

    By default, the URL uses the localhost address (127.0.0.1) and port number 8000.

  3. Add the candid endpoint to access the Candid web interface followed by the required canisterId parameter and canister identifier.

    For example, the full URL should look similar to the following but with the ic:_canister_identifier_ that was returned by the dfx canister install command:

    http://localhost:8000/candid?canisterId=ic:81DDA04F69F40FEEAC
  4. Review the list of function calls and types defined in the program.

  5. Type a value of the appropriate type for a function or click Lucky to generate a value, then click Call or Query to see the result.

    Favorite cities functions

Stop the local network

  1. Stop the Internet Computer processes running on your local computer by running the following command:

    dfx stop