新着:HeliusがLight Protocolを買収
DAS APIを使用してコレクション内のすべてのアセットを返す方法
ブログ/開発

Solana Dev 101 - DAS APIを使用してコレクション内のすべてのNFTを取得する

デベロッパーリレーションズ責任者LinkedInのHunter Davis
読了時間:6分

概要

Digital Asset Standard(DAS)APIは、Solana上の通常アセットと圧縮アセット(トークン、NFTなど)を統合する、新たにリリースされたインターフェースです。圧縮アセットの導入により、Solana開発者は複数のエンドポイントを使用することなく、ウォレット、コレクション、または権限に関連付けられたすべてのアセットを効率的に取得できるようになりました。DAS APIはバックグラウンドでインデックス化されるため、開発者は非常に高いパフォーマンスで呼び出せます。DASを使用すれば、時間のかかるgPA呼び出しをなくし、情報取得プロセスを効率化できます。getAssetsByOwnerエンドポイントでは、オンチェーンのコレクションIDを使用して、特定のコレクションに属するすべてのアセットのメタデータとオフチェーン情報にアクセスできます。

このチュートリアルでは、DAS APIを使用してMad Ladsコレクションからアセット情報を取得する方法を説明します。現在のコードベースに沿って進める場合は、GitHubリポジトリをこちらから確認できます。詳細については、充実したDAS APIドキュメントもご覧ください。

前提条件

  • Node.jsがインストールされていること(組み込みのfetchを使用する場合はv18.0以降)。
  • JavaScriptの基礎知識。

環境のセットアップ

  1. このプロジェクト用にcollectionという名前のフォルダを作成します。
  2. collectionフォルダ内に、assetList.jsという名前のファイルを作成します。このファイルに関数を記述します。
  3. Developer PortalでAPIキーを作成します。RPCsに移動してMainnet RPCリンクをコピーします。このチュートリアルでは、それをURL変数として使用します。
  4. テスト用のデモコレクションのCertified Collection IDを取得します。ここでは、コレクションIDがJ1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9wであるMad Ladsを使用します。特定のNFTを表示する際に、Magic Edenなどのマーケットプレイスでオンチェーンのコレクションアドレスを確認できます。

手順

DAS APIを使用してNFTコレクションからアセット情報を取得する方法を説明します。

1. getAssetsByGroup関数を作成する

まず、コレクションに関連するすべてのアセットを取得する関数を作成します。この関数内に、DAS APIへのPOSTリクエストを記述します。

最初に、非同期関数を定義します。

コード
const { promises : fs } = require("fs");
const url = `https://rpc.helius.xyz/?api-key=`;

const getAssetsByGroup = async () => {
// Code goes here.
};

getAssetsByGroup();

このセクションでは、ファイルシステム操作を処理するためにfsモジュールをインポートし、RPC URLを指定して、getAssetsByGroup関数を宣言しています。

<api-key>を、Developer Portalで取得したAPIキーに置き換えてください。

2. DASへのPOSTリクエストを作成する

getAssetsByGroup関数を定義し、開始ページとリクエストの戻り値のパラメータを指定します。メソッドのドキュメントに合わせて、fetch関数を使用します。

コード
console.time('getAssetsByGroup');
let page = 1;
let assetList = [];

console.time('getAssetsByGroup')でタイマーを開始し、現在のページ用の変数と、取得したアセットを格納する空の配列を初期化します。

fetchとawaitを使用して、指定したurlエンドポイントに非同期POSTリクエストを送信します。

コード
try {
   while (page) {
    const response = await fetch(url, {
      method: 'POST',

次に、page変数がfalseでない限り、APIからデータを取得し続けるwhileループに入ります。

続いて、HTTPリクエストを送信する非同期処理であるfetchとawaitを使用します。APIエンドポイントのurlを指定し、メソッドを「POST」に設定します。これは、リクエストのbodyでサーバーにデータを送信することを意味します。

コード
headers: {
	'Content-Type': 'application/json',
},

リクエストのheadersでは、「Content-Type」を「application/json」に設定します。これにより、JSONデータを送信していることがサーバーに伝わります。

コード
body: JSON.stringify({
	jsonrpc: '2.0',
	id: 'my-id',
	method: 'getAssetsByGroup',
	params: {
		groupKey: 'collection',
		groupValue: 'J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w',
		page: page,
		limit: 1000,
	},
}),

次に、リクエストのbodyを設定します。これは、エンドポイントに送信できる形式へ文字列化するJSONオブジェクトです。ここでgroupKey(値は「collection」)とgroupValue(オンチェーンのコレクションID)を定義します。

コード
if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

const { result } = await response.json();

ここで、サーバーから正常なレスポンスが返されなかった場合に捕捉するエラー処理を開始します。リクエストが成功した場合は、レスポンスをJSON形式で返します。

urlに有効なAPIキーが設定されていない場合、エラーが発生する可能性があります。

3. 新しいアセットをリストに追加する

前のセクションでは、ページが1に設定されているときにgetAssetsByGroupが動作するようにしました。しかし、結果のすべてのページを処理する設定はまだ行っていません。次に設定します。

コード
assetList.push(...result.items);
    if (result.total !== 1000) {
      page = false;
    } else {
      page++;
    }
  }

このコードは、レスポンス内の項目をassetList配列に追加します。結果の合計数が上限の1,000と等しくない場合、ループを終了するためにpageをfalseに設定します。

4. アセットをファイルに記録する

取得したアセット情報を外部のJSONファイルに保存するには、次のコードを追加します。

コード
const resultData = {
    totalResults: assetList.length,
    results: assetList,
  };

  await fs.writeFile('results.json', JSON.stringify(resultData, null, 2));
	console.log('Results saved to results.json')
  console.timeEnd('getAssetsByGroup');

このコードは、結果の合計数とassetList配列で構成されるresultDataオブジェクトを作成します。fs.writeFileを使用して、results.jsonという名前のJSONファイルにデータを書き込みます。最後に、確認メッセージをログに出力し、console.timeEndでタイマーを終了します。

5. エラー処理を実装する

次に、サーバーリクエストで発生する可能性のある失敗に対処するためのセーフティネットを設計します。これは、次の設定で実現できます。このコードブロックは、リクエストの実行中に問題が発生した場合、コンソールにエラーメッセージを出力します。

コード
} catch (error) {
    console.error('Error occurred:', error);
}

有効なオンチェーンのコレクションIDを指定していない場合、リクエストでエラーが発生する可能性があります。

完成したコード

assetList.jsファイルは、次のコードスニペットのようになります。

コード
const { promises : fs } = require("fs");
const url = `https://rpc.helius.xyz/?api-key=`;

const getAssetsByGroup = async () => {
  console.time('getAssetsByGroup'); // Start the timer
  let page = 1;
  let assetList = [];

try {
   while (page) {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        jsonrpc: '2.0',
        id: 'my-id',
        method: 'getAssetsByGroup',
        params: {
          groupKey: 'collection',
          groupValue: 'J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w',
          page: page,
          limit: 1000,
        },
      }),
    });
		if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }
    const { result } = await response.json();

    assetList.push(...result.items);
    if (result.total !== 1000) {
      page = false;
    } else {
      page++;
    }
  }

  const resultData = {
    totalResults: assetList.length,
    results: assetList,
  };

  await fs.writeFile('results.json', JSON.stringify(resultData, null, 2));
	console.log('Results saved to results.json')
  console.timeEnd('getAssetsByGroup');

	} catch (error) {
    console.error('Error occurred:', error);
  }

};

getAssetsByGroup();

結果

ファイルが上記のコードと同じ内容になったら、ターミナルでnode assetList.jsコマンドを実行してリクエストを開始できます。これにより、results.jsonファイルが生成されます。

処理が完了すると、結果がresults.jsonファイルに保存されたことと、アセットの取得にかかった時間がコンソールに表示されます。今回、Node.jsを使用してMad Ladsのオンチェーンコレクションのアセット情報を取得したところ、平均で9.27秒かかりました。

results.jsonファイルを開くと、返された結果の合計数とアセットの詳細が表示されます。これらは、クエリしたコレクションに属する個々のNFTを表します。

返されるデータをさらにカスタマイズするには、画像、所有者、その他の有用なメタデータなど、特定の情報を抽出できます。

results.json

コード
{
  "totalResults": 9967,
  "results": [
    {
      "interface": "Custom",
      "id": "GVPX9rXRXo9SVGktJCzA3Qb9v263kQzEyAWsgX3LL8P5",
      "content": {
        "$schema": "https://schema.metaplex.com/nft1.0.json",
        "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/859.json",
        "files": [
          {
            "uri": "https://madlads.s3.us-west-2.amazonaws.com/images/859.png",
            "cdn_uri": "https://cdn.helius.services/cdn-cgi/image//https://madlads.s3.us-west-2.amazonaws.com/images/859.png",
            "mime": "image/png"
          },
          {
            "uri": "https://arweave.net/qJ5B6fx5hEt4P7XbicbJQRyTcbyLaV-OQNA1KjzdqOQ/859.png",
            "cdn_uri": "https://cdn.helius.services/cdn-cgi/image//https://arweave.net/qJ5B6fx5hEt4P7XbicbJQRyTcbyLaV-OQNA1KjzdqOQ/859.png",
            "mime": "image/png"
          }
        ],
        "metadata": {
          "attributes": [
            {
              "value": "Male",
              "trait_type": "Gender"
            },
            {
              "value": "Galaxy",
              "trait_type": "Type"
            },
            {
              "value": "Galaxy",
              "trait_type": "Expression"
            },
            {
              "value": "Gambler",
              "trait_type": "Hat"
            },
            {
              "value": "Galaxy",
              "trait_type": "Eyes"
            },
            {
              "value": "Dark Windsor",
              "trait_type": "Clothing"
            },
            {
              "value": "Grey",
              "trait_type": "Background"
            }
          ],
          "description": "Fock it.",
          "name": "Mad Lads #859",
          "symbol": "MAD"
        },
        "links": {
          "external_url": null
        }
      },
      "authorities": [
        {
          "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW",
          "scopes": [
            "full"
          ]
        }
      ],
      "compression": {
        "eligible": false,
        "compressed": false,
        "data_hash": "",
        "creator_hash": "",
        "asset_hash": "",
        "tree": "",
        "seq": 0,
        "leaf_id": 0
      },
      "grouping": [
        {
          "group_key": "collection",
          "group_value": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w"
        }
      ],
      "royalty": {
        "royalty_model": "creators",
        "target": null,
        "percent": 0.042,
        "basis_points": 420,
        "primary_sale_happened": true,
        "locked": false
      },
      "creators": [
        {
          "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv",
          "share": 0,
          "verified": true
        },
        {
          "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW",
          "share": 100,
          "verified": true
        }
      ],
      "ownership": {
        "frozen": false,
        "delegated": false,
        "delegate": null,
        "ownership_model": "single",
        "owner": "GX6KFMFS6yZGJzuZ28Q5Cbk9RN8Wv8UmNP2abcC4kcM2"
      },
      "supply": null,
      "mutable": true
    }, ...
    // Addtional Items
]

これにより、返されたアセット全体が表示されます。ここからさらに絞り込み、トークンアドレス、所有者、その他のさまざまなメタデータ情報のみを返すことができます。

まとめ

おめでとうございます。新たにリリースされたDigital Asset Standard(DAS)APIを使用して、10k規模のコレクションからすべてのアセットを取得できました。要点は次のとおりです。

  • DAS APIは、Solana dAppsでアセットを取得するための効率的な方法を提供します。
  • このメソッドは、通常のコレクションと圧縮コレクションの両方に対応しています。
  • DAS APIを使用すると、15秒未満で有用なメタデータと所有権情報にアクセスできます。

DAS APIを使用すると、Solana上のdAppsにおけるアセット取得を効率化できます。情報を収集するために複数のAPI呼び出しを行う必要はなく、1つのエンドポイントを使用するだけです。

今後のチュートリアルでは、アセット取得をさらに効率化するその他の選択肢もいくつか紹介します。

ぜひDiscordに参加して、ご質問を投稿してください。

‍

Heliusを購読

Solana開発の最新情報や新しい記事の公開通知を受け取れます

拡大画像