Schema augmentation
Schema augmentationDynamic variables [PRO]

Dynamic variables [PRO]

The GraphQL query below receives variable $limit to know how many posts to retrieve, and the type of the variable, Int, must be declared in the operation:

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

This is the expected behavior in GraphQL, in which we provide the variable value in a JSON dictionary defined in the same document:

{
  "limit": 3
}

This is "static" behavior, shared by many languages. In PHP, for instance, the function arguments can indicate their type, as in the code below, where input $number is defined to be an integer:

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

Now, when declaring a variable within the body of the PHP function, we do not indicate its type; the variable's type is determined by the context in which the variable is used. In the code below, assigning an integer value to $double will make this variable be an integer:

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

Thanks to custom directives, the GraphQL server can provide a similar behavior and support dynamic variables, where a dynamic variable has its value obtained when resolving the query in the server, instead of being provided by the client.

The Multiple Query Execution extension of Gato GraphQL ships with custom directive @export, which allows exporting the value of a field into a (dynamic) variable, and then we can read the value of this variable in a field argument from a different operation:

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

The variable $userName is dynamic, and there is no need to define its type (String) in the operation that uses it (GetPostsContainingString). The GraphQL server already understands the context.

If we attempt to use the variable value with a mismatching type, as in the following query (where an Int is expected but the dynamic variable is a 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
  }
}

...then the GraphQL server fails coercing the value, and returns an error:

{
  "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 spec

This functionality is currently not part of the GraphQL spec, but it has been requested in: