{"meta":{"title":"从 REST 迁移到 GraphQL","intro":"了解从 GitHubREST API 迁移到 GitHub“GraphQL API” 的最佳做法和注意事项。","product":"GraphQL API","breadcrumbs":[{"href":"/zh/graphql","title":"GraphQL API"},{"href":"/zh/graphql/guides","title":"指南"},{"href":"/zh/graphql/guides/migrating-from-rest-to-graphql","title":"从 REST 迁移到 GraphQL"}],"documentType":"article"},"body":"# 从 REST 迁移到 GraphQL\n\n了解从 GitHubREST API 迁移到 GitHub“GraphQL API” 的最佳做法和注意事项。\n\n## API 逻辑差异\n\nGitHub 提供两个 API：REST API 和 GraphQL API。 有关 GitHub 的 API 的更多信息，请参阅 [比较GitHub的 REST API 和 GraphQL API](/zh/rest/about-the-rest-api/comparing-githubs-rest-api-and-graphql-api)。\n\n从 REST 迁移到 GraphQL 代表了 API 逻辑的一次重大转变。 作为样式的 REST 与作为规范的 GraphQL 之间的差异使得很难—且通常不可取—以一对一方式将 REST API 调用替换为 GraphQL API 查询。 我们在下面提供了具体的迁移示例。\n\n将代码从 [REST API](/zh/rest) 迁移到 GraphQL API：\n\n* 查看 [GraphQL 规范](https://spec.graphql.org/June2018/)\n* 查看GitHub的 [GraphQL 架构](/zh/graphql/reference)\n* 请考虑您当前与 GitHub REST API 进行交互的任何现有代码。\n* 使用[全局节点 ID](/zh/graphql/guides/using-global-node-ids) 引用 API 版本之间的对象\n\nGraphQL 的重要优势包括：\n\n* [只获取你需要的数据，不多不少](#example-getting-the-data-you-need-and-nothing-more)\n* [嵌套字段](#example-nesting)\n* [强类型](#example-strong-typing)\n\n下面是每种优势的示例。\n\n## 示例：获取所需数据，仅此而已\n\n通过单次 REST API 调用可以检索组织成员列表。\n\n```shell\ncurl -v https://api.github.com/orgs/:org/members\n```\n\n如果您的目标是仅检索成员名称和头像链接，REST 有效负载中将包含多余数据。 但是，GraphQL 查询仅返回您指定的数据：\n\n```graphql\nquery {\n    organization(login:\"github\") {\n    membersWithRole(first: 100) {\n      edges {\n        node {\n          name\n          avatarUrl\n        }\n      }\n    }\n  }\n}\n```\n\n考虑另一个示例：检索拉取请求列表并检查每个请求是否可合并。 对 REST API 的调用可检索拉取请求列表及其[摘要陈述](/zh/rest#summary-representations)：\n\n```shell\ncurl -v https://api.github.com/repos/:owner/:repo/pulls\n```\n\n确定拉取请求是否可合并需要分别检索每个拉取请求，查看其[详细陈述](/zh/rest#detailed-representations)（大型有效负载），并检查它的 `mergeable` 属性是真还是假：\n\n```shell\ncurl -v https://api.github.com/repos/:owner/:repo/pulls/:number\n```\n\n使用 GraphQL，可以仅检索每个拉取请求的 `number` 和 `mergeable` 特性：\n\n```graphql\nquery {\n    repository(owner:\"octocat\", name:\"Hello-World\") {\n    pullRequests(last: 10) {\n      edges {\n        node {\n          number\n          mergeable\n        }\n      }\n    }\n  }\n}\n```\n\n## 示例：嵌套\n\n通过嵌套字段查询，可将多个 REST 调用替换为更少的 GraphQL 查询。 例如，使用 **REST API** 检索一个拉取请求及其提交、非审查评论和审查信息，需要分别进行四次调用：\n\n```shell\ncurl -v https://api.github.com/repos/:owner/:repo/pulls/:number\ncurl -v https://api.github.com/repos/:owner/:repo/pulls/:number/commits\ncurl -v https://api.github.com/repos/:owner/:repo/issues/:number/comments\ncurl -v https://api.github.com/repos/:owner/:repo/pulls/:number/reviews\n```\n\n使用 GraphQL API，可以利用嵌套字段通过单个查询检索数据：\n\n```graphql\n{\n  repository(owner: \"octocat\", name: \"Hello-World\") {\n    pullRequest(number: 1) {\n      commits(first: 10) {\n        edges {\n          node {\n            commit {\n              oid\n              message\n            }\n          }\n        }\n      }\n      comments(first: 10) {\n        edges {\n          node {\n            body\n            author {\n              login\n            }\n          }\n        }\n      }\n      reviews(first: 10) {\n        edges {\n          node {\n            state\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n还可以通过为拉取请求编号[替换变量](/zh/graphql/guides/forming-calls-with-graphql#working-with-variables)来扩展此查询的功能。\n\n## 示例：强类型化\n\nGraphQL 架构属于强类型化架构，可使数据处理更加安全。\n\n考虑一个利用 GraphQL [突变](/zh/graphql/reference)向问题或拉取请求添加注释，并错误地将 [`clientMutationId`](/zh/graphql/reference/issues#mutation-addcomment) 值指定为整数而非字符串的示例：\n\n```graphql\nmutation {\n  addComment(input:{clientMutationId: 1234, subjectId: \"MDA6SXNzdWUyMjcyMDA2MTT=\", body: \"Looks good to me!\"}) {\n    clientMutationId\n    commentEdge {\n      node {\n        body\n        repository {\n          id\n          name\n          nameWithOwner\n        }\n        issue {\n          number\n        }\n      }\n    }\n  }\n}\n```\n\n执行此查询将返回错误，并指定此操作的预期类型：\n\n```json\n{\n  \"data\": null,\n  \"errors\": [\n    {\n      \"message\": \"Argument 'input' on Field 'addComment' has an invalid value. Expected type 'AddCommentInput!'.\",\n      \"locations\": [\n        {\n          \"line\": 3,\n          \"column\": 3\n        }\n      ]\n    },\n    {\n      \"message\": \"Argument 'clientMutationId' on InputObject 'AddCommentInput' has an invalid value. Expected type 'String'.\",\n      \"locations\": [\n        {\n          \"line\": 3,\n          \"column\": 20\n        }\n      ]\n    }\n  ]\n}\n```\n\n用引号括住 `1234` 可将此值从整数转换为字符串，预期类型为：\n\n```graphql\nmutation {\n  addComment(input:{clientMutationId: \"1234\", subjectId: \"MDA6SXNzdWUyMjcyMDA2MTT=\", body: \"Looks good to me!\"}) {\n    clientMutationId\n    commentEdge {\n      node {\n        body\n        repository {\n          id\n          name\n          nameWithOwner\n        }\n        issue {\n          number\n        }\n      }\n    }\n  }\n}\n```"}