Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Effectuer des appels avec GraphQL

Comment vous authentifier auprès de l’API GraphQL, comment créer et exécuter des requêtes et des mutations.

L’endpoint GraphQL

Une API REST comporte de nombreux points de terminaison. Avec l’API GraphQL, le point de terminaison reste le même, quelle que soit l’opération effectuée. Pour la version en production, cet endpoint est :

https://api.iiens.net/graphql/v1

Important

Le standard GraphQL est pensé pour ne pas avoir de changement cassant. Mais si un jour une nouvelle version majeure de l’API devait être publiée, le suffixe /v1 garanti que votre application ne sera pas impactée.

Communication avec GraphQL

Les opérations GraphQL étant constituées de JSON sur plusieurs lignes, ARISE recommande d’utiliser des clients GraphQL pour effectuer des appels GraphQL. Vous pouvez également utiliser curl ou toute autre bibliothèque prenant en charge le protocole HTTP.

En REST, les verbes HTTP déterminent l’opération effectuée. En GraphQL, vous fournissez un corps encodé en JSON, que vous effectuiez une requête ou une mutation, le verbe HTTP est donc POST.

Pour interroger GraphQL dans une commande curl, effectuez une requête POST avec des données JSON. Les données doivent contenir une chaîne appelée query :

curl -H "Authorization: bearer TOKEN" -X POST --data " \
  { \
    \"query\": \"query { profile { id }}\" \
  } \
" https://api.iiens.net/graphql/v1

Note

La valeur de la chaîne "query" doit échapper les retour à la ligne, sinon le schéma ne l’analysera pas correctement. Pour le corps de la requête POST, utilisez des doubles guillemets à l’extérieur et des doubles guillemets échappés à l’intérieur.

Requêtes et mutations

Les deux types d’opérations autorisées dans l’API GraphQL d’ARISE sont les requêtes (queries) et les mutations. Si l’on compare GraphQL à REST, les requêtes fonctionnent comme des requêtes GET, tandis que les mutations fonctionnent comme des requêtes POST/PATCH/DELETE. Le nom de la mutation détermine la modification qui est exécutée.

Les requêtes et les mutations ont une structure similaire, mais présentent quelques différences importantes.

Requêtes (queries)

Les requêtes GraphQL renvoient uniquement les données que vous spécifiez. Pour formuler une requête, vous devez spécifier des champs à l’intérieur d’autres champs (également appelés sous-champs imbriqués) jusqu’à ce que vous n’obteniez plus que des valeurs scalaires.

Les requêtes sont structurées comme suit :

query {
  OBJET-JSON-À-RENVOYER
}

Pour un exemple concret, consultez la section Exemple de requête.

Mutations

Pour créer une mutation, vous devez spécifier trois éléments :

  1. Nom de la mutation. Le type de modification que vous souhaitez effectuer.
  2. Objet d’entrée. Les données que vous souhaitez envoyer au serveur, composées de champs d’entrée. Transmettez-le en tant qu’argument au nom de la mutation.
  3. Objet de charge utile (payload). Les données que vous souhaitez recevoir du serveur, composées de champs de retour. Transmettez-le en tant que corps du nom de la mutation.

Les mutations sont structurées comme suit :

mutation {
  MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {
    MUTATION-NAME-PAYLOAD
  }
}

Dans cet exemple, l’objet d’entrée est MutationNameInput et l’objet de charge utile est MutationNamePayload.

Pour un exemple concret, consultez Exemple de mutation.

Utilisation des variables

Les variables permettent de rendre les requêtes plus dynamiques et plus puissantes, et elles peuvent réduire la complexité lors du passage d’objets d’entrée de mutation.

Voici un exemple de requête avec une seule variable :

query Profile($numberOfGroups: Int!) {
  profile {
    name
    groups(last: $numberOfGroups) {
      nodes {
        group {
          name
        }
      }
    }
  }
}
{
  "numberOfGroups": 10
}

L’utilisation des variables se déroule en trois étapes :

  1. Définissez la variable en dehors de l’opération dans un objet variables :
{
  "numberOfGroups": 10
}

L’objet doit être au format JSON valide. Cet exemple montre un type de variable Int simple, mais il est possible de définir des types de variables plus complexes, tels que des objets d’entrée. Vous pouvez également définir plusieurs variables ici.

  1. Transmettez la variable à l’opération en tant qu’argument :
query Profile($numberOfGroups: Int!) {

L’argument est une paire clé-valeur, où la clé est le nom commençant par $ (par exemple, $numberOfGroups), et la valeur est le type (par exemple, Int). Ajoutez un ! pour indiquer si le type est obligatoire. Si vous avez défini plusieurs variables, incluez-les ici en tant qu’arguments multiples.

  1. Utilisez la variable dans l’opération :
groups(last: $numberOfGroups) {

Dans cet exemple, nous remplaçons le nombre de référentiels à récupérer par la variable. Nous spécifions un type à l’étape 2 car GraphQL impose un typage fort.

Ce processus rend l’argument de la requête dynamique. Nous pouvons désormais simplement modifier la valeur dans l’objet variables tout en conservant le reste de la requête inchangé.

L’utilisation de variables comme arguments vous permet de mettre à jour dynamiquement les valeurs dans l’objet variables sans modifier la requête.

Exemple de requête

Examinons une requête plus complexe afin de replacer ces informations dans leur contexte.

La requête suivante interroge le groupe arise, son nom et son site web, trouve les 20 membres les plus récents et renvoie nom complet ainsi que l’année (1A, 2A, etc.) de chaque membre :

query {
  group(group: {id: "arise"}) {
    name
    website
    members(last: 20, filter: {role: {is: ADMIN}}) {
      nodes {
        user {
          name
          schoolYear
        }
        role {
          value
        }
      }
    }
  }
}

Examinons le code ligne par ligne :

  • query {

    Comme nous souhaitons lire des données sur le serveur sans les modifier, l’opération query est l’opération racine. (Si vous ne spécifiez pas d’opération, query est également l’opération par défaut.)

  • group(group: {id: "arise"}) {

    Pour débuter la requête, nous voulons trouver un objet group. La validation du schéma indique que cet objet nécessite un argument group.

  • name website

    Nous récupérons les champs name et website de l’objet Group.

  • members(last: 20, filter: {role: {is: ADMIN}}) {

    Pour prendre en compte tous les membres du groupe, nous appelons l’objet members. (Nous pourrions interroger un seul membre d’un groupe, mais cela nous obligerait à connaître l’identifiant du membre que nous voulons renvoyer et à le fournir en tant qu’argument.)

    Quelques détails concernant l’objet members :

    • La documentation indique que cet objet est de type GroupMembershipConnection.
    • La validation du schéma indique que cet objet nécessite un nombre de résultats (first ou last) en tant qu’argument ; nous fournissons donc 20.
    • La documentation indique également que cet objet accepte un argument filter, qui est de type UserMemberFilter. Pour trouver uniquement les admins, nous attribuons à la clé role la valeur {is: ADMIN}.
  • nodes {

    Nous savons que members est une connexion car il est de type GroupMembershipConnection. Pour récupérer des données sur des membres individuels, nous devons accéder au nœud via nodes.

    La documentation sur GroupMembershipConnection indique que le nœud à l’extrémité de cette connexion est un objet GroupMembership.

  • Nous savons désormais que nous récupérons un objet GroupMembership, nous pouvons consulter la documentation et spécifier les champs que nous souhaitons renvoyer :

    user {
      name
      schoolYear
    }
    role {
      value
    }
    

    Ici, nous spécifions les champs name, schoolYear sur l’objet User et value sur l’object CurrentGroupMembershipInheritance.

    Pourquoi renvoyer la value de role ? Les rôles étant hérité, un OWNER est ADMIN au sens du filtre dans l’objet members. Pour ne récupérer que les admins, il aurait fallu spécifier {strict: true}.

Exemple de mutation

Warning

Work In Progress

Les modification ne sont pas persistante sur l’API. Il faut passer par le LDAP.

Annexe : HTTP

Le serveur GraphQL prend en charge la méthode HTTP POST pour les opérations de requête et de mutation, et accepte également la méthode GET pour les opérations de type query.

Requête POST et corps de la requête

Une requête POST GraphQL standard doit définir application/json comme en-tête Content-Type et inclure un corps encodé en JSON sous la forme suivante :

{
  "query": "...",
  "operationName": "...",
  "variables": { "myVariable": "someValue", ... },
  "extensions": { "myExtension": "someValue", ... }
}

Le paramètre query est obligatoire et contient le texte source d’un document GraphQL. Notez que le terme query est ici trompeur : le document peut contenir n’importe quelle opération GraphQL valide (mutation par exemple).

Les paramètres operationName, variables et extensions sont facultatifs. Le paramètre operationName n’est obligatoire que si le document contient plusieurs opérations query.

Notez que si l’en-tête Content-type est absent de la requête du client, le serveur répondra avec un code d’état 4xx. Comme pour l’en-tête Accept, l’encodage utf-8 est supposé pour un corps de requête de type application/json lorsque cette information n’est pas explicitement fournie.

Requête GET et paramètres

Note

Bien que la spécification GraphQL rende optionnel le support de la méthode GET, l’API d’ARISE la prend en charge.

Lors de la réception d’une requête HTTP GET, le document GraphQL doit être fourni dans le paramètre query de la chaîne de requête (query string). Par exemple, si nous souhaitons exécuter la requête GraphQL suivante :

{
  buildInfo {
    version
  }
}

Cette requête peut être envoyée via une requête HTTP GET comme suit :

https://api.iiens.net/graphql/v1?query={buildInfo{version}}

Warning

Certains clients comme cURL ne pourront pas exécuter la requête sans modification préalable. Il faut encoder la chaîne de caractère pour qu’elle soit “URL safe”.

curl "https://api.iiens.net/graphql/v1?query=%7BbuildInfo%7Bversion%7D%7D"

Les variables de requête peuvent être envoyées sous forme de chaîne encodée en JSON dans un paramètre de requête supplémentaire appelé variables. Si la requête contient plusieurs opérations nommées, un paramètre de requête operationName peut être utilisé pour déterminer laquelle doit être exécutée.

Choix d’une méthode HTTP

Lors du choix d’une méthode HTTP pour une requête GraphQL, plusieurs points doivent être pris en compte.

La méthode HTTP GET ne peut être utilisée que pour les opérations de requête ; ainsi, si un client demande l’exécution d’une opération de mutation, il doit utiliser la méthode POST à la place.

Les clients sont encouragés à exploiter la méthode GET pour faciliter la mise en cache HTTP. Cependant, comme les chaînes de caractères des documents GraphQL peuvent être assez longues pour les opérations complexes, les paramètres de requête peuvent dépasser les limites imposées par les navigateurs et les CDN sur la longueur des URL.