⚛ Qu'est ce que GraphQL ?
Introduction
GraphQL est un protocole d'API créé par 2 ingénieurs de Facebook, qui souhaitaient répondre à des soucis de chargement de données et de réduction de bande passante.
C'est pourquoi on peut y retrouver des fonctionnalités de base que l'ont ne retrouve pas systématiquement dans d'autres protocoles d'API qui sont :
- Sélection des champs retournés par le serveur (optimisation du payload et du volume de la réponse)
- Imbrication de champs (aka: Nesting, possibilité de demander des attributs d'une entité rattachée à une autre)
- Mutualisation des requêtes en un appel HTTP (aka: Batch)
- Temp réel grâce à un système PUB/SUB basé sur WebSocket
- Schéma déclaratif des données et des fonctions (toutes les entités de l'API sont décrites en un fichier disponible sur demande et qui permet donc de la documenter)
- Gestion d'erreur côté client (si la requête est mal formée, en regard de la syntaxe et du Schéma de l'API, c'est le client qui détecte l'erreur et non le serveur)
Principes
Query
C'est le mot clé pour définir une requête de lecture des données de l'API (équivalent en REST
: GET
).
Elles permettent donc de récupérer les informations d'un objet ou d'une fonction, mais pas d'en modifier la valeur.
Spécificité de l'API Cautioneo
Les ID
des objets sont uniques et sont encapsulés dans une chaîne de caractère base64 contenant l'ID interne (uuid) de l'objet et comportant une date d'expiration et une signature.
Ainsi lesID
obtenus depuis l'API ne peuvent être utilisés que dans cette API et ne peuvent provenir que de cette API, ils ne peuvent donc être générés / devinés par un acteur extérieur.
Certains objets comme User
ont une date d'expiration dans leur ID
ce qui les protège d'une fuite de donnée ou d'une interception par un acteur extérieur.
Mutation
C'est le mot clé pour définir une requête d'écriture des données de l'API (équivalent en REST
: POST
/ PUT
/ PATCH
/ DELETE
).
Elles permettent donc de modifier un objet et de récupérer comme dans une query
les valeurs de cet objet.
Chez Cautioneo nous utilisons la syntaxe Relay pour matérialiser les attributs à enregistrer / modifier via l'argument input
de la fonction de mutation.
Afin de marquer si un argument est obligatoire ou non, la syntaxe GraphQL utilise un !
après le type d'argument lorsqu'il est obligatoire. Ce qui donne :
mutation uneMutation(
$arg1: ID! # Required
$arg2: String # Optional
)
ClientMutationId
Les mutations peuvent être effectuées en Batch (ex: créer plusieurs comptes utilisateur en 1 requête), cependant l'ordre dans lequel sont traitées ses mutations n'est pas nécessairement l'ordre transmit par le client au serveur.
Afin de faire la corrélation entre les mutations d'une même requête, chaque fonctione de mutation peut inclure un argument clientMutationId
qui est une chaîne de caratère choisie par le client de l'API.
Cette valeur sera retournée à l'identique par le serveur dans la réponse de chaque mutation, ce qui permet au client de ne pas mélanger les résultats des mutations.
mutation createTwoUsers($email1: String!, $email2: String!) {
createUser(input: { email: $email1, clientMutationId: "fonction1" }) {
user {
id
email
}
clientMutationId
}
createUser(input: { email: $email2, clientMutationId: "fonction2" }) {
user {
id
email
}
clientMutationId
}
}
Subscription
Les Subscription
sont des requêtes Pub/Sub qui vous permettent d'être alerté en temps réel d'un événement. C'est le serveur d'API qui détermine les types de Subscription
possibles, leur nomenclature et leurs arguments.
Elles ont la même syntaxe qu'une mutation.
Le mot clé Subscription
étant réservé à cet usage, c'est pour cela que l'objet représentant un dossier Cautioneo s'appelle CautioneoSubscription
ou PbiSubscription
.
Fragments
Les fragments sont des éléments de requête pré-construits et réutilisables.
Ils peuvent être fournis par l'API elle-même ou définie côté client afin de simplifier l'écriture des requêtes.
Elles se présente sous cette forme :
fragment UserFragment on User {
email
firstName
lastName
gender
}
Et peuvent être utilisé dans les requêtes comme ceci :
query getUserWithFragment($id: ID!) {
node(id: $id) {
id
...UserFragment
}
}
GraphQL Relay
C'est une extension du protocole GraphQL qui a pour but de définir certains principes qui restent libres dans l'utilisation du protocole. En voici une liste non exhaustive, mais qui est utilisée dans l'API Cautioneo
Node
Chaque objet de l'API Cautioneo dérive de l'interface Node et peut donc être obtenu via son ID par une seule et même query : node
Ainsi pour obtenir un User
on peut s'addresser à l'API comme ceci :
query getUser($id: ID!) {
node(id: $id) {
... on User {
email
}
}
}
Pagination
La pagination se fait par curseur et non pas numéro de page.
Cela permet de garder une cohérence lors du parcours d'une collection si celle-ci est amenée à changer.
Cette technique est souvent appliquée lors de l'implémentation de fil d'actualité (Twitter, Facebook, Instagram, etc...)
Une explication très complète est disponible ici, mais en voici un résumé :
# Nous souhaitons obtenir la liste des documents d'un dossier :
query {
node(id: "ID") {
... on CautioneoSubscription {
documents(
first: 10 # Obtenir les 10 premiers enregistrements
last: 10 # Obtenir les 10 derniers enregistrements
after: "CURSOR" # Marqueur de début de liste (pour obtenir les enregistrements après ce marqueur)
before: "CURSOR" # Marqueur de fin de liste (pour obtenir les enregistrements avant ce marqueur)
) {
edges { # collection des enregistrements
cursor # identifiant de l'enregistrement dans la liste afin de pouvoir la parcourir à partir de cet enregistrement
node { # un enregistrement auquel il faut demander les attributs souhaités
id
}
}
totalCount # Nombre total d'enregistrements
pageInfo {
hasNextPage # Y-a-t-il d'autres enregistrement après ?
hasPreviousPage # Y-a-t-il d'autres enregistrement avant ?
startCursor # Premier curseur de la liste
endCursor # Dernier curseur de la liste
}
}
}
}
Implémentations
Vous pouvez retrouver l'ensemble des implémentations de GraphQL côté client ou côté serveur sur le site de graphql.org
En voici une liste non exhaustive :
Langage | Librairie la plus répandue |
---|---|
PHP | API Platform |
JavaScript | ApolloGraphQL |
Python | Graphene |
Java | GraphQL-Java |
Ruby | GraphQL-Ruby |
Go | GraphQL-Go |