신규: Helius가 Light Protocol을 인수했습니다
DAS API를 사용해 컬렉션의 모든 자산을 반환하는 방법
블로그/개발

Solana Dev 101 - DAS API로 컬렉션의 모든 NFT 가져오기

개발자 관계 총괄LinkedIn의 Hunter Davis
읽는 데 6분

개요

디지털 자산 표준(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. 테스트할 데모 컬렉션의 인증된 컬렉션 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',

다음으로 while 루프를 시작합니다. 이 루프는 page 변수가 false가 아닌 동안 API에서 데이터를 계속 가져옵니다.

그런 다음 HTTP 요청을 보내는 비동기 작업인 fetch과 await을 사용합니다. API 엔드포인트의 url을 지정하고 메서드를 'POST'로 설정합니다. 즉, 요청 본문에 데이터를 담아 서버로 전송합니다.

코드
headers: {
	'Content-Type': 'application/json',
},

요청 헤더에서 '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,
	},
}),

이어서 요청 본문을 구성합니다. 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
]

반환된 자산 전체가 표시됩니다. 여기서 데이터를 더 세분화해 토큰 주소, 소유자 및 다양한 메타데이터 정보만 반환할 수 있습니다.

마무리

축하합니다! 새로 출시된 디지털 자산 표준(DAS) API를 사용해 10k 규모 컬렉션의 모든 자산을 성공적으로 조회했습니다. 요약하면 다음과 같습니다.

  • DAS API는 Solana dApp에서 자산을 간편하게 가져올 수 있는 방법을 제공합니다.
  • 이 메서드는 일반 컬렉션과 압축 컬렉션 모두에서 작동합니다.
  • DAS API를 사용하면 15초 이내에 유용한 메타데이터와 소유권 정보에 액세스할 수 있습니다.

DAS API를 사용하면 Solana dApp의 자산 조회 절차를 간소화할 수 있습니다. 정보를 수집하기 위해 여러 API를 호출하는 대신 단일 엔드포인트만 사용하면 됩니다.

향후 튜토리얼에서는 자산을 조회하고 다루기 위한 몇 가지 간소화된 옵션도 살펴보겠습니다.

언제든 Discord에 참여해 궁금한 점을 질문하세요!

‍

Helius 구독하기

최신 Solana 개발 소식을 확인하고 새 게시물 알림을 받아보세요

확대 이미지