当我在 GitHub 的 GraphQL API 中两次调用同一个字段(使用不同的查询)时,为什么我能够绕过分页

jar*_*jar 5 pagination github github-api graphql

在尝试获取用户每个存储库的未解决问题数量时,我注意到了一些我不明白的事情。

当我使用以下查询时,我被要求执行分页(按预期) -

query {
  user(login:"armsp"){
    repositories{
      nodes{
        name
        issues(states: OPEN){
          totalCount
        }
      }
    }    
  }
}

Run Code Online (Sandbox Code Playgroud)

运行上面的错误信息 -

{
  "data": {
    "user": null
  },
  "errors": [
    {
      "type": "MISSING_PAGINATION_BOUNDARIES",
      "path": [
        "user",
        "repositories"
      ],
      "locations": [
        {
          "line": 54,
          "column": 5
        }
      ],
      "message": "You must provide a `first` or `last` value to properly paginate the `repositories` connection."
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

但是,当我执行以下操作时,我实际上得到了对我没有任何意义的所有结果 -

query {
  user(login:"armsp"){
    repositories{
      totalCount
    }
    repositories{
      nodes{
        name
        issues(states: OPEN){
          totalCount
        }
      }
    }   
  }
}
Run Code Online (Sandbox Code Playgroud)

不应该在第二个查询中也要求我进行分页吗?

Dan*_*den 2

太长了;这似乎是一个错误。无法绕过获取资源列表时应用的限制。

像这样限制响应是公共 API 的一个常见功能 - 如果响应可能包含数千或数百万个结果,它将占用大量服务器资源来一次性完成所有结果。允许用户进行此类查询不仅成本高昂,而且存在潜在的安全风险。

Github 的意图似乎是在获取资源列表时始终限制结果的数量。这在 GraphQL 方面没有很好的记录,但与其 REST API的行为相匹配:

默认情况下,返回多个项目的请求将分页至 30 个项目。您可以使用该?page参数指定更多页面。对于某些资源,您还可以使用该参数设置最大为 100 的自定义页面大小?per_page

对于连接,看起来只有当选择集中存在该字段时才会运行对first或参数的检查。这是有道理的,因为这最终是我们想要限制的字段——请求其他字段,例如or ,即使没有限制参数,对于上述问题也是无害的。lastnodestotalDiskUsagetotalDiskUsage

当您考虑GraphQL 如何处理具有相同名称的选择集时,事情会变得很奇怪。无需深入了解具体细节,GraphQL 将允许您多次请求同一字段。如果相关字段有一个选择集,它会有效地将选择集合并为一个选择集。所以

query {
  user(login:"armsp") {
    repositories {
      totalCount
    }
    repositories {
      totalDiskUsage
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

变成并等于

query {
  user(login:"armsp") {
    repositories {
      totalCount
      totalDiskUsage
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

旁注:如果您明确为其中一个字段指定别名,则上述情况不成立,因为这两个字段具有不同的响应名称。

综上所述,从技术上讲,这个查询:

query {
  user(login:"armsp"){
    repositories{
      totalCount
    }
    repositories{
      nodes{
        name
        issues(states: OPEN){
          totalCount
        }
      }
    }   
  }
}
Run Code Online (Sandbox Code Playgroud)

MISSING_PAGINATION_BOUNDARIES也应该因同样的错误而爆炸。事实上,这并不意味着选择集合并在某种程度上破坏了现有的检查。这显然是一个错误。然而,即使这看起来“有效”,它仍然无法绕过 Github 在存储层应用的任何限制——即使利用上述错误,你也最多只能得到 100 个结果。