[英]How to loop trough a paginated API Call in C#?
我正在使用 Web-API“Moralis-API”( https://docs.moralis.io/reference/getwalletnfts ),我從 NFT 錢包中獲取所有 NFT。 我的 API 呼叫如下所示:
using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://deep-index.moralis.io/api/v2/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/nft?chain=eth&format=decimal&normalizeMetadata=false"),
Headers =
{
{ "accept", "application/json" },
{ "X-API-Key", "test" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
API 返回一個 JSON 列表,其中包含具有唯一令牌 ID 的 NFT 和一個“光標”,它是分頁的頁面鍵。 它看起來像這樣:
{
"total": 1600,
"page": 1,
"page_size": 100,
** "cursor": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21QYXJhbXMiOnsid2FsbGV0QWRkcmVzcyI6IjB4ZDhkYTZiZjI2OTY0YWY5ZDdlZWQ5ZTAzZTUzNDE1ZDM3YWE5NjA0NSJ9LCJrZXlzIjpbIjE2NjY3NzIzMDkuNTQyIl0sIndoZXJlIjp7Im93bmVyX29mIjoiMHhkOGRhNmJmMjY5NjRhZjlkN2VlZDllMDNlNTM0MTVkMzdhYTk2MDQ1In0sImxpbWl0IjoxMDAsIm9mZnNldCI6MCwib3JkZXIiOltdLCJ0b3RhbCI6MTYwMCwicGFnZSI6MSwidGFpbE9mZnNldCI6NCwiaWF0IjoxNjY5MTI3OTUxfQ.UGpB3Qc88SJuU97dwVBwfYMkGcuH1-CaFbIKZ9iKots",
** "result": [
{
"token_address": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85",
"token_id": "103040680624633360426956226800459505851045291463662393946817594920946384752224",
"amount": "1",
"owner_of": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"token_hash": "bc95dd2a065742fab91ddd09b2c9a6fc",
"block_number_minted": "16022477",
"block_number": "16022477",
"contract_type": "ERC721",
"name": "Ethereum Name Service",
"symbol": "ENS",
"token_uri": null,
"metadata": null,
"last_token_uri_sync": null,
"last_metadata_sync": "2022-11-22T02:13:59.639Z",
"minter_address": null
},
我的問題是,我不知道如何獲得所有 NFT。 API 每次通話最多只能給我 100 個 NFT。 但我想迭代到下一頁,以獲取所有 NFT。 我認為應該有一個帶循環的解決方案。 我還沒有找到任何關於堆棧溢出的解決方案。 也許有人可以在這里幫助我。 先感謝您。
根據文檔, cursor
屬性用於將結果分頁到下一組。 看起來您需要反序列化響應 object 以同時獲取結果和 cursor 屬性。 我在這方面的工作比我應該做的要多一些,但這是針對您的問題的建議解決方案。
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
namespace Program
{
public static class Program
{
public static async Task Main(string[] args)
{
var client = new HttpClient();
var results = await GetAll(client);
Console.WriteLine(JsonConvert.SerializeObject(results));
}
public static async Task<IList<NftWalletResponseItem>> GetAll(HttpClient client)
{
var cursor = String.Empty;
var results = new List<NftWalletResponseItem>();
var builder = new UriBuilderExt("https", "deep-index.moralis.io")
.Path("/api/v2/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/nft")
.Query("chain", "eth")
.Query("format", "decimal")
.Query("normalizeMetadata", "false");
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = builder,
Headers =
{
{ "Accept", "application/json" },
{ "X-API-Key", "test" },
}
};
for(var previous = -1; previous < results.Count; )
{
previous = results.Count;
if(!String.IsNullOrWhiteSpace(cursor))
{
builder.Query("cursor", cursor);
}
var response = await PerformRequest(client, request);
results.AddRange(response.Result);
}
return results;
}
public static async Task<NftWalletResponse> PerformRequest(HttpClient client, HttpRequestMessage message)
{
var _default = new NftWalletResponse();
using (var response = await client.SendAsync(message))
{
if(response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
NftWalletResponse result = JsonConvert.DeserializeObject<NftWalletResponse>(body) ?? _default;
return result;
}
}
return _default;
}
}
public class NftWalletResponse
{
[JsonProperty("total")]
public int Total { get; set; }
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("page_size")]
public int PageSize { get; set; }
[JsonProperty("cursor")]
public string Cursor { get; set; }
[JsonProperty("result")]
public IList<NftWalletResponseItem> Result { get; set; }
public NftWalletResponse()
{
Cursor = String.Empty;
Result = new List<NftWalletResponseItem>();
}
}
public class NftWalletResponseItem
{
[JsonProperty("amount")]
public int Amount { get; set; }
[JsonProperty("block_number")]
public string BlockNumber { get; set; }
[JsonProperty("block_number_minted")]
public string BlockNumberMinted { get; set; }
[JsonProperty("contract_type")]
public string ContractType { get; set; }
[JsonProperty("last_metadata_sync")]
public DateTime LastMetadataSync { get; set; }
// [JsonProperty("last_token_uri_sync")]
// public <define type> LastTokenUriSync { get; set; }
// [JsonProperty("metadata")]
// public <define type> Metadata { get; set; }
// [JsonProperty("minter_address)]
// public <define type> MinterAddress { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("owner_of")]
public string OwnerOf { get; set; }
[JsonProperty("symbol")]
public string Symbol { get; set; }
[JsonProperty("token_address")]
public string TokenAddress { get; set; }
[JsonProperty("token_hash")]
public string TokenHash { get; set; }
[JsonProperty("token_id")]
public string TokenId { get; set; }
[JsonProperty("token_uri")]
public string TokenUri { get; set; }
public NftWalletResponseItem()
{
BlockNumber = String.Empty;
BlockNumberMinted = String.Empty;
ContractType = String.Empty;
LastMetadataSync = DateTime.UtcNow;
Name = String.Empty;
OwnerOf = String.Empty;
Symbol = String.Empty;
TokenAddress = String.Empty;
TokenHash = String.Empty;
TokenId = String.Empty;
TokenUri = String.Empty;
}
}
public static class ArrayExt {
public static void Deconstruct<T>(this T[] srcArray, out T a0) {
if (srcArray == null || srcArray.Length < 1)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1) {
if (srcArray == null || srcArray.Length < 2)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2) {
if (srcArray == null || srcArray.Length < 3)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
a2 = srcArray[2];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3) {
if (srcArray == null || srcArray.Length < 4)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
a2 = srcArray[2];
a3 = srcArray[3];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4) {
if (srcArray == null || srcArray.Length < 5)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
a2 = srcArray[2];
a3 = srcArray[3];
a4 = srcArray[4];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4, out T a5) {
if (srcArray == null || srcArray.Length < 6)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
a2 = srcArray[2];
a3 = srcArray[3];
a4 = srcArray[4];
a5 = srcArray[5];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6) {
if (srcArray == null || srcArray.Length < 7)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
a2 = srcArray[2];
a3 = srcArray[3];
a4 = srcArray[4];
a5 = srcArray[5];
a6 = srcArray[6];
}
public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6, out T a7) {
if (srcArray == null || srcArray.Length < 8)
throw new ArgumentException(nameof(srcArray));
a0 = srcArray[0];
a1 = srcArray[1];
a2 = srcArray[2];
a3 = srcArray[3];
a4 = srcArray[4];
a5 = srcArray[5];
a6 = srcArray[6];
a7 = srcArray[7];
}
}
public class UriBuilderExt
{
private UriBuilder _builder;
public UriBuilderExt()
{
_builder = new UriBuilder();
}
public UriBuilderExt(string uri)
{
_builder = new UriBuilder(uri);
}
public UriBuilderExt(string schemeName, string hostName)
{
_builder = new UriBuilder(schemeName, hostName);
}
public UriBuilderExt(string schemeName, string hostName, int port)
{
_builder = new UriBuilder(schemeName, hostName, port);
}
public UriBuilderExt(string schemeName, string hostName, int port, string path)
{
_builder = new UriBuilder(schemeName, hostName, port, path);
}
public UriBuilderExt(string schemeName, string hostName, int port, string path, string fragment)
{
_builder = new UriBuilder(schemeName, hostName, port, path, fragment);
}
public UriBuilderExt(Uri uri)
{
_builder = new UriBuilder(uri);
}
public static implicit operator UriBuilderExt(string uri)
{
return new UriBuilderExt(uri);
}
public static implicit operator UriBuilderExt(Uri uri)
{
return new UriBuilderExt(uri);
}
public static implicit operator Uri(UriBuilderExt builder)
{
return builder.Build();
}
public Uri Build()
{
return _builder.Uri;
}
public UriBuilderExt Fragment(string fragment)
{
_builder.Fragment = fragment;
return this;
}
public UriBuilderExt Host(string host)
{
_builder.Host = host;
return this;
}
public UriBuilderExt Password(string password)
{
_builder.Password = password;
return this;
}
public UriBuilderExt Path(string path)
{
_builder.Path = path;
return this;
}
public UriBuilderExt Port(int port)
{
_builder.Port = port;
return this;
}
public UriBuilderExt Query(string key, string value)
{
var qs = new Dictionary<string, string?>();
var builder = new StringBuilder();
foreach(var entry in _builder.Query.Split('&'))
{
var (k, v) = entry.Split('=');
qs.Add(k, v);
}
qs.Add(key, value);
foreach(var entry in qs)
{
if(builder.Length > 0)
{
builder.Append('&');
}
if(!String.IsNullOrEmpty(entry.Value))
{
builder.AppendJoin('=', entry.Key, entry.Value);
}
else
{
builder.Append(entry.Key);
}
}
_builder.Query = builder.ToString();
return this;
}
public UriBuilderExt Scheme(string scheme)
{
_builder.Scheme = scheme;
return this;
}
public UriBuilderExt UserName(string user)
{
_builder.UserName = user;
return this;
}
}
}
原諒一些過度工程,但我已經在 JavaScript 工作了一段時間,我開始期待這方面的一些功能,例如從序列類型中解構賦值,以及更少的手動實現來構建URL(Node 有一個很棒的 API 對應URL.prototype.searchParams
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.