movemove-langaptos

Given a key, how do I read the value from a table via the API?


Imagine I have a move module that looks like this.

Move.toml

[package]
name = 'friends'
version = '1.0.0'

[dependencies.AptosFramework]
git = 'https://github.com/aptos-labs/aptos-core.git'
rev = 'testnet'
subdir = 'aptos-move/framework/aptos-framework'

[addresses]
friends = "81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e"

sources/nicknames.move

module friends::nicknames {
    use std::error;
    use std::signer;
    use std::string::String;
    use aptos_std::table::{Self, Table};

    const ENOT_INITIALIZED: u64 = 0;

    struct Nicknames has key {
        // A map of friends' nicknames to wallet addresses.
        nickname_to_addr: Table<String, address>
    }

    /// Initialize Inner to the caller's account.
    public entry fun initialize(account: &signer) {
        let nicknames = Nicknames {
            nickname_to_addr: table::new(),
        };
        move_to(account, nicknames);
    }

    /// Initialize Inner to the caller's account.
    public entry fun add(account: &signer, nickname: String, friend_addr: address) acquires Nicknames {
        let signer_addr = signer::address_of(account);
        assert!(exists<Nicknames>(signer_addr), error::not_found(ENOT_INITIALIZED));
        let nickname_to_addr = &mut borrow_global_mut<Nicknames>(signer_addr).nickname_to_addr;
        table::add(nickname_to_addr, nickname, friend_addr);
    }
}

I then published the module (to testnet), initialized Nicknames to my account, and then added an entry:

aptos move publish
aptos move run --function-id 81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e::nicknames::initialize
aptos move run --function-id 81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e::nicknames::add --args string:dport address:81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e

Now that my table is on-chain with some data, how would I go about reading the value of the dport key. I think I can use the API for this?


Solution

  • You're right that you can use the API for this! First let's get some information about your table.

    Let's look at the resource you've deployed to your account from the above Move module. First let's construct the struct tag (aka resource ID / handle), it looks like this:

    <account_address>::<module>::<struct_name>
    

    In your case:

    0x81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e::nicknames::Nicknames
    

    Because there can only be one of each resource in an account in the Aptos blockchain, we can use this to uniquely identify the resource in your account. Using this we can then get the table handle. A table handle is a globally unique ID (so, not just within the bounds of your account) that points to that specific table. We need that to make any further queries, so let's get that first:

    $ curl https://fullnode.testnet.aptoslabs.com/v1/accounts/0x81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e/resource/0x81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e::nicknames::Nicknames | jq .
    {
      "type": "0x81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e::nicknames::Nicknames",
      "data": {
        "nickname_to_addr": {
          "handle": "0x64fa842ed2c9da130f0419875e6c101aeea263882fadee3257b13f1bb4d7d41d"
        }
      }
    }
    

    Explaining the above:

    Using this handle, we can now query the API:

    $ cat query.json
    {
      "key_type": "0x1::string::String",
      "value_type": "address",
      "key": "dport"
    }
    
    $ curl -H 'Content-Type: application/json' --data-binary "@query.json" https://fullnode.testnet.aptoslabs.com/v1/tables/0x64fa842ed2c9da130f0419875e6c101aeea263882fadee3257b13f1bb4d7d41d/item
    "0x81e2e2499407693c81fe65c86405ca70df529438339d9da7a6fc2520142b591e"
    

    Explaining the above:

    If hypothetically the key used in the table was more complex, like a struct instead of a single value like a string, you could represent that struct as JSON in the request, e.g.

    {
      "key_type": "0x1::string::String",
      "value_type": "address",
      "key": {
        "first_name": "Ash",
        "last_name": "Ketchum",
      }
    }
    

    This is the extent of what you can do with the API right now. Namely, reading values given you know the key ahead of time. If you want to do the below things, you need to query an indexer:

    I'll write an answer on how to do this later.