# Fetching NFTs, Stacks and Hiro API

## Explanations

### Fetch all NFTs owned by user address

Not we get to the NFT integration step. This is where all the fun starts. We want our app to show a list of all NFTs owned by the user and render them to the `MainMenu` component. For this, we will need to ask query the Stacks API. How can a developer query an online API? Obviously, making URL requests.

### Stacks API URL

The URL we have to request for fetching the stacks API looks like this:

```jsx
https://stacks-node-api.mainnet.stacks.co/extended/v1/tokens/nft/holdings?principal=SP1SCEXE6PMGPAC6B4N5P2MDKX8V4GF9QDE1FNNGJ&&asset_identifiers=SP1SCEXE6PMGPAC6B4N5P2MDKX8V4GF9QDE1FNNGJ.workshop-nfts-integration::duck
```

`https://stacks-node-api.testnet.stacks.co/` is the official Stacks Testnet node and what is after it is the specific API to get the NFTs owned by a given Stacks Address.

### JSON Response Structure

It contains the `principal address` of the user, the `wallet address`, the `smart contract` we want to call and the `function name`. Let’s try it by searching on the browser `url` section and hitting enter. The response from the API looks something like this:

```json
{
  "limit": 50,
  "offset": 0,
  "total": 4,
  "results": [
    {
      "asset_identifier": "ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character",
      "value": {
        "hex": "0x0100000000000000000000000000000002",
        "repr": "u2"
      },
      "block_height": 81902,
      "tx_id": "0xb7a5d44a610d1e1ead9d8e5d34909600fe566550a9c7c63ce8c8bd585f121c89"
    },
    {
      "asset_identifier": "ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character",
      "value": {
        "hex": "0x0100000000000000000000000000000001",
        "repr": "u1"
      },
      "block_height": 81902,
      "tx_id": "0x158d69b6877120d8ea83ee94bb7a90bf9074a8c39854ce55eee0dff5599d9c45"
    },
    {
      "asset_identifier": "ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character",
      "value": {
        "hex": "0x0100000000000000000000000000000003",
        "repr": "u3"
      },
      "block_height": 81902,
      "tx_id": "0x62aeed938b57da7adc473d8017792cc13cee714e4d93fdc829c57b5aaff5b980"
    },
    {
      "asset_identifier": "ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character",
      "value": {
        "hex": "0x0100000000000000000000000000000004",
        "repr": "u4"
      },
      "block_height": 81950,
      "tx_id": "0x19300a8d2663b02e0012be879597372cf4dece9c09128cf2069ea46a98bc07ba"
    }
  ]
}
```

## Code inserted

### Function to get ids of NFTs from JSON&#x20;

Let’s explain what have you seen above. It is observable that we have got a `JSON` structure as a response. This structure contains `limit`, `offset`, `total` and `results`. The `limit` is the maximum number of results we want to get as a response. The default value for the `Stacks API` is `50`. The `offset` represents the value from which we want to fetch the NFTs. This means if, for example, we own `51 NFTs`, we will make two requests `limited` to 50 results. The first will have the `offset 0`, the second will have the `offset 50`. The `total` represents the total number of NFTs the user has for the requested address. Least but not last, we have the `results`. This array will contain either `all the NFTs owned`, if the `total` is lower than the `limit`, or a number of NFTs equal to the `limit` if the `total` is greater than the `limit`. It is easy to find out that we will have to process the result in order to get a list of `ids owned` by the user. For this, we will need a `function` that will look like this:

```jsx
const getIDsNFTsOwned = (jsonNFTHoldings) => {
  let ids = [];
  if (jsonNFTHoldings.results) {
    jsonNFTHoldings.results.map((x) => {
      const id = x.value.repr.substring(1).toString();
      if (id != '') ids.push(id);
    });
  }
  return ids;
};
```

### Function to fetch all the JSON responses from the API and get all the ids of the owned NFTs

You can see above that the function `getIDsNFTsOwned` only has one parameter, `NFTPartsJson`. It refers to the `JSON` response we get as a result after sending the `url` request to the API.

Having these explained, let’s build another function that, `builds` the `url`, `sends` the request to the API, waits to `receive` the response and `interprets` it. The function should look like this:

<pre class="language-jsx"><code class="lang-jsx">const getNFTsOwned = async (accountAddress) => {
  const limit = 50;
  let offsetNFT = 0;
  const asset_identifiers = 'ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character';
  let urlHoldingNFT = `https://stacks-node-api.testnet.stacks.co/extended/v1/tokens/nft/holdings?principal=${accountAddress}&#x26;&#x26;asset_identifiers=${asset_identifiers}`;
  let jsonNFT = await fetch(urlHoldingNFT).then((res) => {
    return res.json();
  });

  let listOfNFTs = [];
  listOfNFTs = getIDsNFTsOwned(jsonNFT);
  const total = jsonNFT.total;
  offsetNFT += limit;
  while (offsetNFT &#x3C; total) {
    const offsetNFTurl = `&#x26;&#x26;offset=${offsetNFT}`;
    const currentUrlHoldingNFT = urlHoldingNFT + offsetNFTurl;
    jsonNFT = await fetch(currentUrlHoldingNFT).then((res) => {
      return res.json();
    });
    listOfNFTs = listOfNFTs.concat(getIDsNFTsOwned(jsonNFT));
    offsetNFT += limit;
  }
<strong>  console.log('NFTs owned: ', listOfNFTs.toString());
</strong>  return listOfNFTs;
};
</code></pre>

### Explanations for the \`getNFTsOwned\` function &#x20;

Let’s split it to make it easier to understand.

```jsx
let offsetNftParts = 0;
const asset_identifiers = 'ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character';
let urlHoldingNFT = `https://stacks-node-api.testnet.stacks.co/extended/v1/tokens/nft/holdings?principal=${accountAddress}&&asset_identifiers=${asset_identifiers}`;
```

The code snippet above shows the way we build the `url` for the API request. We initialize the `offset` to 0, the `asset identifiers` to the value we need containing our `smart contract` and `function name`. Then, we build the `url`. The `accountAddress` is our function `parameter`. After creating the `url string`, we will send the request to the API using `fetch()` method and wait for the response, which will be stored using the `nftParts` variable.

```jsx
let jsonNFT = await fetch(currentUrlHoldingNFT)
  .then((res) => {
    return res.json();
  });
```

Having stored the request’s `result`, we should operate on it. We will obtain a list of ids from the response using the previously explained `getIDsNFTsOwned()` function and storing it into the `listOfNfts` variable. You can see the `function`’s parameter is `await nftParts`, which does nothing but `wait` for the API’s response. A constant to memorize the `total` number of NFTs owned by the user is needed, too. Let’s see it in the console!

```jsx
let listOfNFTs = [];
listOfNFTs = getIDsNFTsOwned(jsonNFT);
const total = jsonNFT.total;
```

Next, we will make sure we have got all the NFTs the user owns and for this we will need to increment the `offset`. Assuring that we have fetched all the NFTs owned by the user will be made using a `while` repetitive structure. As you see below, the execution thread will execute the `while` structure only if the previously incremented `offset` is lower than the `total` number of results. This way we will make sure on the one hand if we have already covered the results, the `while` structure will not be executed at all. On the other hand, if the `total` is greater than the `offset`, we will continue to search for NFTs as many times as needed and every time `increment` the `offset` by the `limit`’s value. As you have seen above, the `limit`’s value equals to `50` by default, so we initialize it. In order to fetch results using an `offset` different to `0`, we have to concatenate `&&offset=value` to our request `url`.

```jsx
offsetNFT += limit;

while (offsetNFT < total) {
  const offsetNFTurl = `&&offset=${offsetNFT}`;
  const currentUrlHoldingNFT = urlHoldingNFT + offsetNFTurl;
  jsonNFT = await fetch(currentUrlHoldingNFT).then((res) => {
    return res.json();
  });
  listOfNFTs = listOfNFTs.concat(getIDsNFTsOwned(jsonNFT));
  offsetNFT += limit;
}
```

The code snippet above shows the fact that for every `while` step, we `concatenate` the new obtained `list of ids` to the previous one. This way we make sure we have stored all the results.

Let’s view the results we have obtained into the console and return them!

```jsx
console.log('NFTs owned: ', listOfNfts.toString());
return listOfNFTs;
```

## Recap how the final code should look in MainMenu file

```jsx
const getIDsNFTsOwned = (jsonNFTHoldings) => {
  let ids = [];
  if (jsonNFTHoldings.results) {
    jsonNFTHoldings.results.map((x) => {
      const id = x.value.repr.substring(1).toString();
      if (id != '') ids.push(id);
    });
  }
  return ids;
};

const getNFTsOwned = async (accountAddress) => {
  const limit = 50;
  let offsetNFT = 0;
  const asset_identifiers = 'ST28AA1PJD8615MPKKKSSX311EWY000G77SFEXXHX.my-nft::character';
  let urlHoldingNFT = `https://stacks-node-api.testnet.stacks.co/extended/v1/tokens/nft/holdings?principal=${accountAddress}&&asset_identifiers=${asset_identifiers}`;
  let jsonNFT = await fetch(urlHoldingNFT).then((res) => {
    return res.json();
  });

  let listOfNFTs = [];
  listOfNFTs = getIDsNFTsOwned(jsonNFT);
  const total = jsonNFT.total;
  offsetNFT += limit;
  while (offsetNFT < total) {
    const offsetNFTurl = `&&offset=${offsetNFT}`;
    const currentUrlHoldingNFT = urlHoldingNFT + offsetNFTurl;
    jsonNFT = await fetch(currentUrlHoldingNFT).then((res) => {
      return res.json();
    });
    listOfNFTs = listOfNFTs.concat(getIDsNFTsOwned(jsonNFT));
    offsetNFT += limit;
  }
  console.log('NFTs owned: ', listOfNFTs.toString());
  return listOfNFTs;
};
```

## This is the branch with the changes done:

{% embed url="<https://github.com/BowTiedDeployer/workshop-nft-integration/tree/dapp/2-fetch-nfts-owned>" %}
branch dapp/2-fetch-nfts-owned
{% endembed %}

You can check the exact changes in this commit referring to them

{% embed url="<https://github.com/BowTiedDeployer/workshop-nft-integration/commit/5182629178e261c4a09a637d13509c7a7cb52700>" %}
commit 5182629178e261c4a09a637d13509c7a7cb52700
{% endembed %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.degenlab.io/gamefistacks/workshop/nft-web-app-integration/fetching-nfts-stacks-and-hiro-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
