{"author":{"address":"0x99DD70Cb7d9F8B85EDeE2a454E56478Cd0b0EaEF","user":"https://learnblockchain.cn/people/23775"},"content":{"body":"## 背景简介\r\n\r\nGraphQL 是由 Facebook（现 Meta）于 2012 年开发并在 2015 年开源的一种数据查询语言。与传统的 REST API 相比，GraphQL 提供了一种更加灵活高效的方式来请求和操作数据。通过其强类型系统和声明式查询语法，开发者可以在一次请求中精准获取所需的数据，避免了冗余数据的传输和多次 API 调用的麻烦。\r\n\r\nGraphQL 的发展经历了几个重要阶段：\r\n1. 诞生阶段（2012-2015）\r\n   - GraphQL 诞生于 Facebook 内部，用于解决其移动应用在数据请求上的性能瓶颈。与 REST API 的固定端点设计不同，GraphQL 提供了一个动态单一端点，通过查询语言定义所需数据的结构。\r\n2. 开源推广（2015-2018）\r\n   - 在 2015 年 GraphQL 开源后，其简单直观的语法和高效的数据交互模型迅速吸引了开发者的关注。随着 Relay 和 Apollo 等 GraphQL 工具的出现，生态逐步丰富，GraphQL 开始被广泛应用于 Web 开发中。\r\n3. 成熟与生态扩展（2018-至今）\r\n   - GraphQL 不再局限于 Web 应用，而是逐渐扩展到微服务架构、移动端和区块链等领域。例如，GitHub 和 Shopify 等知名企业率先使用 GraphQL 替代 REST API。2023 年后，GraphQL 逐渐成为新兴区块链平台（如 Sui）的核心 API 查询语言，为去中心化网络提供灵活的交互方式。\r\n\r\n## GraphQL在Sui中的应用\r\n\r\nGraphQL 被引入 Sui 区块链，旨在提供一种灵活高效的数据交互机制。通过 GraphQL 查询，开发者能够精确访问区块链上的动态数据（如交易、事件、对象等），实现高度自定义的链上分析和数据聚合需求。Sui GraphQL 还支持分片查询、分页和变量定义，为开发者提供更丰富的操作空间，同时优化了区块链节点的查询性能。\r\n\r\nGraphQL 的引入不仅加速了 Sui 生态的开发效率，也为去中心化应用（DApps）的构建提供了强有力的支持，特别是在构建 DeFi、NFT 和社交应用时，开发者可以通过简单的查询语句获取复杂的数据组合。\r\n\r\n通过本笔记的学习，我们可以了解如何在 Sui 中应用 GraphQL 进行高效开发，同时深入掌握其语法和操作模式。\r\n\r\n## 1. Headers（HTTP头）\r\n\r\nGraphQL 服务允许通过 HTTP 头对请求行为进行调整。以下是常见头的用途：\r\n- `x-sui-rpc-version`: 指定 RPC 版本（当前仅支持一个版本）。\r\n- `x-sui-rpc-show-usage`: 返回包含查询复杂度的额外信息。\r\n\r\n### 示例请求：\r\n\r\n```bash\r\ncurl -i -X POST https://sui-mainnet.mystenlabs.com/graphql \\\r\n     --header 'x-sui-rpc-show-usage: true'                 \\\r\n     --header 'Content-Type: application/json'             \\\r\n     --data '{\r\n          \"query\": \"query { epoch { referenceGasPrice } }\"\r\n     }'\r\n```\r\n\r\n### 示例响应：\r\n返回数据包括 `referenceGasPrice` 和额外的查询复杂度信息，例如输入/输出节点数、查询深度等。\r\n\r\n## 2. Variables（变量）\r\n\r\n变量允许动态输入，用以提高查询的可重用性。定义变量时需使用 `$` 符号，并指定类型（如 `Int`）。变量在查询体中通过名称引用。\r\n\r\n### 示例请求：\r\n\r\n```graphql\r\nquery ($epochID: Int) {\r\n  epoch(id: $epochID) {\r\n    referenceGasPrice\r\n  }\r\n}\r\n```\r\n\r\n### 变量输入：\r\n\r\n```json\r\n{\r\n   \"epochID\": 100\r\n}\r\n```\r\n\r\n### 注意事项：\r\n- 未声明或赋值的变量会导致查询失败。\r\n- 在线 IDE 可在 Variables 面板输入 JSON 格式变量。\r\n\r\n## 3. Fragments（片段）\r\n\r\n片段是可重用的查询片段，用于结构化和优化查询。以下片段示例展示了如何查询 Move 值。\r\n\r\n### 示例查询：\r\n\r\n```graphql\r\nquery DynamicField {\r\n  object(\r\n    address: \"0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac\"\r\n  ) {\r\n    dynamicField(\r\n      name: {\r\n        type: \"0x2::kiosk::Listing\",\r\n        bcs: \"NLArx1UJguOUYmXgNG8Pv8KbKXLjWtCi6i0Yeq1VhfwA\",\r\n      }\r\n    ) {\r\n      ...DynamicFieldSelect\r\n    }\r\n  }\r\n}\r\n\r\nfragment DynamicFieldSelect on DynamicField {\r\n  name {\r\n    ...MoveValueFields\r\n  }\r\n  value {\r\n    ...DynamicFieldValueSelection\r\n  }\r\n}\r\n\r\nfragment MoveValueFields on MoveValue {\r\n  type {\r\n    repr\r\n  }\r\n  data\r\n  bcs\r\n}\r\n```\r\n\r\n### 特点：\r\n- 使用片段如 `MoveValueFields`，避免冗长重复的字段定义。\r\n\r\n## 4. Pagination（分页）\r\n\r\nGraphQL 支持分页查询，用于处理大量结果。常见参数包括：\r\n- `first`: 限制返回的最大数量，从开头截取。\r\n- `after`: 从指定游标（不包括）后开始。\r\n- `last`: 限制返回的最大数量，从结尾截取。\r\n- `before`: 从指定游标（不包括）前开始。\r\n\r\n### 分页示例：\r\n查询第 97 个 epoch 的交易块：\r\n\r\n```graphql\r\nquery {\r\n  epoch(id: 97) {\r\n    transactionBlocks(first: 10) {\r\n      pageInfo {\r\n        hasNextPage\r\n        endCursor\r\n      }\r\n      nodes {\r\n        digest\r\n        sender {\r\n          address\r\n        }\r\n        gasInput {\r\n          gasPrice\r\n          gasBudget\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### 注意事项：\r\n- 游标（Cursor）为分页的唯一有效标识，不应手动生成。\r\n- 分页具有一致性，即分页过程中数据保持网络某一检查点的状态。\r\n\r\n## 5. Limits（使用限制）\r\n\r\nGraphQL 服务对查询进行了以下限制：\r\n- 速率限制：每分钟的最大请求次数。\r\n- 复杂度限制：包括最大查询深度、节点数量和查询负载大小等。\r\n\r\n### 示例查询限制：\r\n\r\n```graphql\r\n{\r\n  serviceConfig {\r\n    maxQueryDepth\r\n    maxQueryNodes\r\n    maxOutputNodes\r\n    maxPageSize\r\n    requestTimeoutMs\r\n  }\r\n}\r\n```\r\n\r\n### 优化建议：\r\n- 简化查询结构以降低复杂度。\r\n- 使用分页避免单次请求返回过多数据。\r\n\r\n## 快速入门：探索GraphQL Schema\r\n\r\n通过 Sui 提供的在线 IDE，你可以轻松查看支持的 GraphQL schema。\r\n\r\n- [主网](https://sui-mainnet.mystenlabs.com/graphql)\r\n- [测试网](https://sui-testnet.mystenlabs.com/graphql)\r\n\r\n在 IDE 中：\r\n- 按 `Ctrl+K` 打开 Schema 搜索。\r\n- 点击左上角书本图标查看文档。\r\n\r\n### 示例：\r\n\r\n1. **获取最新纪元的参考Gas价格**\r\n\r\n```graphql\r\nquery {\r\n  epoch {\r\n    referenceGasPrice\r\n  }\r\n}\r\n```\r\n\r\n2. **查询历史纪元信息**\r\n\r\n获取特定纪元（例如第100纪元）的详细信息，包括质押奖励、参考Gas价格、检查点数量和总Gas费用等。\r\n\r\n```graphql\r\nquery {\r\n  epoch(id: 100) {\r\n    epochId\r\n    totalStakeRewards\r\n    referenceGasPrice\r\n    totalCheckpoints\r\n    totalGasFees\r\n    storageFund {\r\n      totalObjectStorageRebates\r\n      nonRefundableBalance\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n3. **基于交易摘要查找交易区块**\r\n\r\n通过交易摘要 (digest) 查找交易详细信息，例如 Gas 提供方地址、预算和执行效果。\r\n\r\n```graphql\r\nquery {\r\n  transactionBlock(digest: \"FdKFgsQ9iRrxW6b1dh9WPGuNuaJWMXHJn1wqBQSqVqK2\") {\r\n    gasInput {\r\n      gasSponsor {\r\n        address\r\n      }\r\n      gasPrice\r\n      gasBudget\r\n    }\r\n    effects {\r\n      status\r\n      timestamp\r\n      epoch {\r\n        epochId\r\n        referenceGasPrice\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n4. **过滤和分页查询交易记录**\r\n\r\n查询最近10条非系统交易：\r\n\r\n```graphql\r\nquery {\r\n  transactionBlocks(last: 10, filter: {kind: PROGRAMMABLE_TX}) {\r\n    nodes {\r\n      digest\r\n      kind {\r\n        __typename\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n查询涉及特定对象的交易：\r\n\r\n```graphql\r\nquery ($objectID: SuiAddress!) {\r\n  transactionBlocks(filter: {changedObject: $objectID}) {\r\n    nodes {\r\n      sender {\r\n        address\r\n      }\r\n      digest\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n**变量**：\r\n\r\n```json\r\n{\r\n  \"objectID\": \"0x11c6ae8432156527fc2e12e05ac7db79f2e972510a823a4ef2e670f27ad7b52f\"\r\n}\r\n```\r\n5. **动态字段与对象操作** \r\n\r\nGraphQL可以通过别名和片段来优化查询结构。例如：\r\n\r\n获取动态字段：\r\n\r\n```graphql\r\nquery DynamicField {\r\n  object(address: \"0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac\") {\r\n    dynamicField(\r\n      name: {\r\n        type: \"0x2::kiosk::Listing\",\r\n        bcs: \"NLArx1UJguOUYmXgNG8Pv8KbKXLjWtCi6i0Yeq1VhfwA\"\r\n      }\r\n    ) {\r\n      name {\r\n        ...MoveValueFields\r\n      }\r\n      value {\r\n        __typename\r\n        ... on MoveObject {\r\n          hasPublicTransfer\r\n          contents {\r\n            ...MoveValueFields\r\n          }\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\nfragment MoveValueFields on MoveValue {\r\n  type {\r\n    repr\r\n  }\r\n  data\r\n  bcs\r\n}\r\n```\r\n6. **执行交易**\r\n\r\n执行交易需要两个参数：序列化的交易数据 (txBytes) 和签名 (signatures)。\r\n\r\n```graphql\r\nmutation ($tx: String!, $sigs: [String!]!) {\r\n  executeTransactionBlock(txBytes: $tx, signatures: $sigs) {\r\n    errors\r\n    effects {\r\n      status\r\n      epoch {\r\n        startTimestamp\r\n      }\r\n      gasEffects {\r\n        gasSummary {\r\n          computationCost\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n变量：\r\n```\r\n{\r\n  \"tx\": \"AAACACAZXApmrHgzTs3FGDyXWka+wmMCy2IwOdKLmTWHb5PnFQEASlCnLAw4qfzLF3unH9or5/L7YpOlReaSEWfoEwhTqpavSxAAAAAAACCUFUCOn8ljIxcG9O+CA1bzqjunqr4DLDSzSoNCkUvu2AEBAQEBAAEAALNQHmLi4jgC5MuwwmiMvZEeV5kuyh+waCS60voE7fpzAa3v/tOFuqDvQ+bjBpKTfjyL+6yIg+5eC3dKReVwghH/rksQAAAAAAAgxtZtKhXTr1zeFAo1JzEqVKn9J1H74ddbCJNVZGo2I1izUB5i4uI4AuTLsMJojL2RHleZLsofsGgkutL6BO36c+gDAAAAAAAAQEIPAAAAAAAA\",\r\n  \"sigs\": [\r\n    \"AB4ZihXxUMSs9Ju5Cstuuf/hvbTvvycuRk2TMuagLYNJgQuAeXmKyJF9DAXUtL8spIsHrDQgemn4NmojcNl8HQ3JFqhnaTC8gMX4fy/rGgqgL6CDcbikawUUjC4zlkflwg==\"\r\n  ]\r\n}\r\n```\r\n通过上述案例，开发者可以掌握如何使用GraphQL高效查询和操作Sui区块链资源。GraphQL的灵活性和强大的数据操作能力，为开发Move语言的链上应用提供了重要支持。\r\n\r\n总结\r\n\r\n通过 GraphQL for Sui RPC，可以灵活地获取区块链数据，适配多种应用场景。掌握 Headers、变量、片段和分页等技巧，能够显著提升查询效率。同时需注意使用限制，以确保服务的高效和稳定。\r\n\r\n\u003e **请用微信关注《HOH水分子》公众号，我们将持续分享和制作变成语言教程，让大家对编程产生化学反应。**\r\n![HOH_QR.jpg](https://img.learnblockchain.cn/attachments/2024/11/4h04Aovz6738b68758d43.jpg)","title":"（十八）Move语言学习笔记：GraphQL for Sui RPC (Beta)"},"history":null,"timestamp":1734008810,"version":1}