Ampliación del esquema
Ampliación del esquemaVariables dinámicas

Variables dinámicas

La consulta GraphQL siguiente recibe la variable $limit para saber cuántas entradas recuperar, y el tipo de la variable, Int, debe declararse en la operación:

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

Este es el comportamiento esperado en GraphQL, en el que proporcionamos el valor de la variable en un diccionario JSON definido en el mismo documento:

{
  "limit": 3
}

Este es un comportamiento "estático", compartido por muchos lenguajes. En PHP, por ejemplo, los argumentos de las funciones pueden indicar su tipo, como en el código siguiente, donde el input $number se define como un entero:

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

Ahora, al declarar una variable dentro del cuerpo de la función PHP, no indicamos su tipo; el tipo de la variable se determina por el contexto en el que se usa la variable. En el código siguiente, asignar un valor entero a $double hará que esta variable sea un entero:

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

Gracias a las directivas personalizadas, el servidor GraphQL puede proporcionar un comportamiento similar y soportar variables dinámicas, donde una variable dinámica obtiene su valor al resolver la consulta en el servidor, en lugar de ser proporcionado por el cliente.

La extensión Ejecución de múltiples consultas de Gato GraphQL viene con la directiva personalizada @export, que permite exportar el valor de un campo a una variable (dinámica), y luego podemos leer el valor de esta variable en un argumento de campo de una operación diferente:

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

La variable $userName es dinámica, y no hay necesidad de definir su tipo (String) en la operación que la usa (GetPostsContainingString). El servidor GraphQL ya entiende el contexto.

Si intentamos usar el valor de la variable con un tipo no coincidente, como en la siguiente consulta (donde se espera un Int pero la variable dinámica es un 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
  }
}

...entonces el servidor GraphQL falla al coercer el valor, y devuelve un 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"
      }
    }
  ]
}

Especificación de GraphQL

Esta funcionalidad actualmente no forma parte de la especificación de GraphQL, pero se ha solicitado en: