Schema 扩充
Schema 扩充动态变量

动态变量

下面的 GraphQL Query 接收变量 $limit 来确定要获取的文章数量,变量的类型 Int 必须在操作中声明:

query GetPosts($limit: Int) {
  posts(limit: $limit) {
    id
    title
  }
}

这是 GraphQL 中的预期行为,我们在同一文档中的 JSON 字典里提供变量的值:

{
  "limit": 3
}

这是「静态」行为,许多语言都有这种特性。例如在 PHP 中,可以在函数参数中指定类型,如下面的代码所示,输入 $number 被定义为整数:

function double(int $number): int
{
  return $number * 2;
}

而在 PHP 函数体内声明变量时,不需要指定其类型;变量的类型由其使用的上下文决定。在下面的代码中,将整数值赋给 $double 会使该变量成为整数:

function double(int $number): int
{
  // This var is an integer, but we don't need to declare it
  $double = $number * 2;
  return $double;
}

借助自定义指令,GraphQL 服务器可以提供类似的行为并支持动态变量。动态变量的值在服务器解析 Query 时获取,而不是由客户端提供。

Gato GraphQL 的 Multiple Query Execution 扩展附带了自定义指令 @export,它允许将字段的值导出到(动态)变量中,然后可以在不同操作的字段参数中读取该变量的值:

query ExportLoggedInUserName {
  me {
    name @export(as: "userName")
  }
}
 
query GetPostsContainingString
  @depends(on: "ExportLoggedInUserName")
{
  posts(filter: { search: $userName }) {
    id
    title
  }
}

变量 $userName 是动态的,无需在使用它的操作(GetPostsContainingString)中定义其类型(String)。GraphQL 服务器已经理解其上下文。

如果尝试使用类型不匹配的变量值,如下面的 Query(期望 Int,但动态变量是 String):

query ExportDynamicVariable {
  _echo(value: "Hello world!") @export(as: "stringVar") # Exported: String
}
 
query UseVariable
  @depends(on: "ExportDynamicVariable")
{
  posts(
    pagination: {
      limit: $stringVar # Expected: Int, received: String
    }
  ) {
    id
  }
}

……GraphQL 服务器将在类型转换值时失败,并返回错误:

{
  "errors": [
    {
      "message": "Cannot cast value 'Hello world!' for type 'Int'",
      "locations": [
        {
          "line": 10,
          "column": 13
        }
      ],
      "extensions": {
        "path": [
          "{limit: $stringVar}",
          "(pagination: {limit: $stringVar})",
          "posts(pagination: {limit: $stringVar}) { ... }",
          "query UseVariable @depends(on: \"ExportDynamicVariable\") { ... }"
        ],
        "type": "QueryRoot",
        "field": "posts(pagination: {limit: $stringVar}) { ... }",
        "id": "root",
        "code": "gql@5.6.1[16]",
        "specifiedBy": "https:\/\/spec.graphql.org\/draft\/#sec-Values-of-Correct-Type"
      }
    }
  ]
}

GraphQL 规范

此功能目前不属于 GraphQL 规范,但已在以下地方被提出: