Importing standard library functions

In this tutorial, you are going to write a simple program that enables you to store and look up telephone numbers. This tutorial illustrates how to import and use a few basic standard library functions.

For this tutorial, the standard library functions are defined in the list and assocList library files and enable you to work with lists as linked key-value pairs. In this example, the key is a name and the value is the phone text string associated with that name.

This program supports the following types of function calls:

  • The insert function call accepts the name and phone key-value pair as input stored in the book variable.

  • The lookup function is a query that uses the specified the name as input to find the associated phone number.

Before you begin

Before starting the tutorial, verify the following:

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

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

This tutorial takes approximately 10 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 phonebook
  4. Change to your project directory by running the following command:

    cd phonebook

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. In this tutorial, you will create a new main.mo file for the simple phone number lookup program.

To modify the default template source code:

  1. Open the src/phonebook/main.mo file in a text editor and delete the existing content.

  2. Copy and paste the following sample code into the main.mo file:

    // Import standard library functions for lists
    
    import L "mo:stdlib/list";
    import A "mo:stdlib/assocList";
    
    // The PhoneBook actor.
    actor {
    
        // Type aliases make the rest of the code easier to read.
        public type Name = Text;
        public type Phone = Text;
    
        // The actor maps names to phone numbers.
        var book: A.AssocList<Name, Phone> = L.nil<(Name, Phone)>();
    
        // An auxiliary function checks whether two names are equal.
        func nameEq(l: Name, r: Name): Bool {
            return l == r;
        };
    
        // A shared invokable function that inserts a new entry
        // into the phone book or replaces the previous one.
        public func insert(name: Name, phone: Phone): async () {
            let (newBook, _) = A.replace<Name, Phone>(book, name, nameEq, ?phone);
            book := newBook;
        };
    
        // A shared read-only query function that returns the (optional)
        // phone number corresponding to the person with the given name.
        public query func lookup(name: Name): async ?Phone {
            return A.find<Name, Phone>(book, name, nameEq);
        };
    };

Build and deploy the program

You now have a program that you can compile into an executable WebAssembly module that you can deploy on your local client network.

To build the program executable:

  1. Change to the root directory for your project, if necessary.

    For example, if your project root directory is ~/ic-projects/phonebook, run the following command:

    cd ~/ic-projects/phonebook
  2. Build the WebAssembly executable by running the following command:

    dfx build --skip-frontend
  3. Start the Internet Computer network on your local computer by running the following command:

    dfx start

    When you run the dfx start command without the --background option, the processes start in the current terminal so you need to open a new terminal shell to continue.

  4. Open a new terminal shell, then change the root directory for your project.

    For example:

    cd ~/ic-projects/phonebook
  5. Deploy your phonebook project on the local network by running the following command:

    dfx canister install phonebook

Add names and numbers using the insert function

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

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

  1. Use the dfx canister call command to call the canister phonebook using the insert function and pass it a name and phone number by running the following command:

    dfx canister call phonebook insert '("Chris Lynn", "01 415 792 1333")'
  2. Add a second name and number pair by running the following command:

    dfx canister call phonebook insert '("Maya Garcia", "01 408 395 7276")'
  3. Verify that the command returns the number associated with "Chris Lynn" using the lookup function by running the following command:

    dfx canister call phonebook lookup '("Chris Lynn")'

    The command returns output similar to the following:

    (opt "01 415 792 1333")
  4. Try to call the lookup function with the number associated with "Maya Garcia" by running the following command:

    dfx canister call phonebook lookup '("01 408 395 7276")'

    Note that, in this case, the command returns (none) because the phone number is not a key associated with the "Maya Garcia" name entry.

  5. Try to call the lookup function again to return the phone numbers for both "Maya Garcia" and "Chris Lynn" by running the following command:

    dfx canister call phonebook lookup '("Maya Garcia","Chris Lynn")'

    Because the program is written to return one value for one key, the command only returns the phone number associated with the first key—the "Maya Garcia" name entry. For example:

    (opt "01 408 395 7276")

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, then click Call or Query to see the result.

Stop the local network

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

    dfx stop

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 change the source code so that instead of a program that inserts and looks up a current key-value (name-phone) pair to create a program that stores contact information similar to a database "record" in which a primary key is associated with multiple fields. In this example, your program might enable users or another program to add information—such as a home phone number, a cell phone number, an email address, and a street address—and selectively return all or specific field values.