Schema-uitbreiding
Schema-uitbreidingDynamische variabelen

Dynamische variabelen

De onderstaande GraphQL-query ontvangt de variabele $limit om te weten hoeveel posts er opgehaald moeten worden, en het type van de variabele, Int, moet worden gedeclareerd in de operatie:

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

Dit is het verwachte gedrag in GraphQL, waarbij we de variabelewaarde opgeven in een JSON-woordenboek dat in hetzelfde document is gedefinieerd:

{
  "limit": 3
}

Dit is "statisch" gedrag, dat door veel talen wordt gedeeld. In PHP kunnen de functieargumenten bijvoorbeeld hun type aangeven, zoals in de onderstaande code, waarbij invoer $number is gedefinieerd als een geheel getal:

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

Wanneer je nu een variabele declareert binnen de body van de PHP-functie, geef je het type ervan niet aan; het type van de variabele wordt bepaald door de context waarin de variabele wordt gebruikt. In de onderstaande code zorgt het toewijzen van een gehele getalwaarde aan $double ervoor dat deze variabele een geheel getal wordt:

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

Dankzij aangepaste directives kan de GraphQL-server een vergelijkbaar gedrag bieden en dynamische variabelen ondersteunen, waarbij een dynamische variabele zijn waarde krijgt tijdens het oplossen van de queries op de server, in plaats van door de client te worden aangeleverd.

De Multiple Query Execution-extensie van Gato GraphQL wordt geleverd met de aangepaste directive @export, waarmee je de waarde van een veld kunt exporteren naar een (dynamische) variabele, waarna je de waarde van deze variabele kunt lezen in een veldargument van een andere operatie:

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

De variabele $userName is dynamisch en het is niet nodig om het type ervan (String) te definiëren in de operatie die het gebruikt (GetPostsContainingString). De GraphQL-server begrijpt de context al.

Als we proberen de variabelewaarde te gebruiken met een niet-overeenkomend type, zoals in de volgende query (waarbij een Int wordt verwacht maar de dynamische variabele een String is):

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
  }
}

...dan mislukt het omzetten van de waarde door de GraphQL-server en wordt er een fout geretourneerd:

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

Deze functionaliteit maakt momenteel geen deel uit van de GraphQL-specificatie, maar is aangevraagd in: