Arise Programming Interface (API)
L’API d’ARISE (Administrateurs du Réseau Informatique et des Services aux Étudiants) offre une grande souplesse et permet de définir précisément les données souhaitées. Elle est ouverte aux arisers mais également aux étudiants et associations.
Aperçu
Voici quelques liens rapides pour vous aider à vous familiariser avec l’API :
À propos de GraphQL
Le langage de requête de données GraphQL est :
- Une spécification. La spécification détermine la validité du schéma sur le serveur API. Le schéma détermine la validité des requêtes du client.
- Fortement typé. Le schéma définit le système de types d’une API et toutes les relations entre les objets.
- Introspectif. Un client peut interroger le schéma pour obtenir des détails sur celui-ci.
- Hiérarchique. La structure d’un appel GraphQL reflète la structure des données JSON qu’il renvoie. Les champs imbriqués vous permettent de rechercher et de recevoir uniquement les données que vous spécifiez en un seul aller-retour.
- Une couche applicative. GraphQL n’est ni un modèle de stockage ni un langage de requête de base de données. Le graphe fait référence aux structures de graphe définies dans le schéma, où les nœuds définissent des objets et les arêtes définissent les relations entre les objets. L’API parcourt et renvoie les données de l’application en fonction des définitions du schéma, indépendamment de la manière dont les données sont stockées.
Pourquoi ARISE utilise GraphQL
ARISE a choisi GraphQL car cette technologie offre une flexibilité nettement supérieure pour nos utilisateurs et applications internes. La possibilité de définir précisément les données souhaitées (et uniquement celles-ci) constitue un avantage considérable par rapport aux endpoint API REST traditionnels. GraphQL permet de remplacer plusieurs requêtes REST par un seul appel pour récupérer les données spécifiées.
Pour en savoir plus sur les raisons qui ont poussé ARISE à miser sur GraphQL, consultez le README du projet.
Cas d’usage
- Modifier ses données personnelles [Work in Progress]
- Récupérer les informations d’un utilisateur via OAuth
- Obtenir une donnée en particulier sur l’ensemble des utilisateurs
- Nécessite une autorisation préalable d’ARISE
Guides
Ces guides présentent comment utiliser l’API GraphQL. Bien que personnalisé pour ARISE, ces guides restent génériques et présentent surtout le standard GraphQL.
- Introduction à GraphQL
- Effectuer des appels avec GraphQL
- Explorateur GraphQL
- Utilisation des clients GraphQL
- Pagination
Introduction à GraphQL
Terminologie et concepts utiles pour utiliser l’API GraphQL d’ARISE.
Schéma
Un schéma définit le système de types d’une API GraphQL. Il décrit l’ensemble complet des données possibles (objets, champs, relations, etc.) auxquelles un client peut accéder. Les requêtes émises par le client sont validées et exécutées par rapport au schéma. Un client peut obtenir des informations sur le schéma par introspection. Un schéma réside sur le serveur de l’API GraphQL.
Champ
Un champ est une unité de données que vous pouvez extraire d’un objet. Comme l’indique la documentation officielle de GraphQL : “Le langage de requête GraphQL consiste essentiellement à sélectionner des champs sur des objets.”
La spécification officielle précise également à propos des champs :
Toutes les opérations GraphQL doivent spécifier leurs sélections jusqu’au niveau des champs qui renvoient des valeurs scalaires afin de garantir une réponse sans ambiguïté.
Cela signifie que si vous essayez de renvoyer un champ qui n’est pas un scalaire, la validation du schéma générera une erreur. Vous devez ajouter des sous-champs imbriqués jusqu’à ce que tous les champs renvoient des scalaires.
Note
Un scalaire désigne un type “simple” comme un string, un booléen ou un entier. Il n’est pas possible de demander à retourner implicitement tous les champs d’un objet. Il faut lister explicitement tous les champs scalaires.
Argument
Un argument est un ensemble de paires clé-valeur associées à un champ spécifique. Certains champs nécessitent un argument. Les mutations nécessitent un objet d’entrée en tant qu’argument.
Héritage
Un schéma GraphQL peut utiliser le terme implements pour définir comment un objet hérite d’une interface.
Voici un exemple fictif de schéma définissant l’interface X et l’objet Y :
interface X {
unChamp: String!
unAutreChamp: String!
}
type Y implements X {
unChamp: String!
unAutreChamp: String!
nouveauChamp: String!
}
Cela signifie que l’objet Y nécessite les mêmes champs/arguments/types de retour que l’interface X, tout en ajoutant de nouveaux champs spécifiques à l’objet Y. (Le signe ! indique que le champ est obligatoire.)
Connexion (Connection)
Les connexions vous permettent d’interroger des objets associés dans le cadre d’un même appel. Grâce aux connexions, vous pouvez utiliser un seul appel GraphQL là où vous auriez dû effectuer plusieurs appels vers une API REST.
Il est utile de le visualiser comme un graphe : des points reliés par des lignes. Les points sont des nœuds, les lignes sont des arêtes. Une connexion définit une relation entre des nœuds.
Arête (Edge)
Les arêtes représentent les connexions entre les nœuds. Lorsque vous interrogez une connexion, vous parcourez ses arêtes pour accéder à ses nœuds. Chaque champ edges comporte un champ node et un champ cursor. Les curseurs sont utilisés pour la pagination. Pour plus d’informations, consultez la page sur la Pagination.
Nœud (Node)
Nœud est un terme générique désignant un objet. Vous pouvez rechercher un nœud directement ou accéder à des nœuds associés via une connexion. Si vous spécifiez un node qui ne renvoie pas de scalaire, vous devez inclure des sous-champs jusqu’à ce que tous les champs renvoient des scalaires.
Introspection
GraphQL est introspectif. Cela signifie que vous pouvez interroger un schéma GraphQL pour obtenir des informations le concernant.
- Interrogez
__schemapour répertorier tous les types définis dans le schéma et obtenir des détails sur chacun d’entre eux :
query {
__schema {
types {
name
kind
description
fields {
name
}
}
}
}
- Interrogez
__typepour obtenir des détails sur n’importe quel type :
query {
__type(name: "User") {
name
kind
description
fields {
name
}
}
}
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
/v1garanti 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êtePOST, 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 :
- Nom de la mutation. Le type de modification que vous souhaitez effectuer.
- 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.
- 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 :
- 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.
- 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.
- 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
queryest l’opération racine. (Si vous ne spécifiez pas d’opération,queryest é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 argumentgroup. -
name websiteNous récupérons les champs
nameetwebsitede l’objetGroup. -
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 (
firstoulast) en tant qu’argument ; nous fournissons donc 20. - La documentation indique également que cet objet accepte un argument
filter, qui est de typeUserMemberFilter. Pour trouver uniquement les admins, nous attribuons à la clérolela valeur{is: ADMIN}.
- La documentation indique que cet objet est de type
-
nodes {Nous savons que
membersest une connexion car il est de typeGroupMembershipConnection. Pour récupérer des données sur des membres individuels, nous devons accéder au nœud vianodes.La documentation sur
GroupMembershipConnectionindique que le nœud à l’extrémité de cette connexion est un objetGroupMembership. -
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,schoolYearsur l’objetUseretvaluesur l’objectCurrentGroupMembershipInheritance.Pourquoi renvoyer la
valuederole? Les rôles étant hérité, unOWNERestADMINau sens du filtre dans l’objetmembers. 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.
Explorateur GraphQL
L’explorateur GraphQL utilise le client GraphiQL. Pour commencer, rendez vous sur explore.api.iiens.net.
Note
D’autres client peuvent être utilisés pour réaliser vos requêtes, comme la commande
curlpar exemple. L’avantage de l’explorateur est l’authentification automatique via AriseID Connect.
Important
L’explorateur vous authentifie via OAuth avec le scope
api. Le jeton possède les mêmes permissions que votre utilisateur, sans restriction. Par exemple, un admin ARISE pourra accéder aux champs sensibles des utilisateurs.Un client non authentifié est accessible à l’URL https://api.iiens.net/graphql.
Tip
Des explications plus poussées sur la syntaxe GraphQL sont retrouvables sur la page Introduction à GraphQL

Une fois connecté avec AriseID Connect, vous devriez vous retrouver sur une page similaire à la capture ci-dessus. À gauche, le contenu de la requête. Cela ressemble à du JSON et c’est normal car c’est la forme des données qui nous seront retournées. En bas l’onglet Variables permet d’ajouter des paramètres à notre requête pour la rendre réutilisable. L’onglet Headers permet entre autres d’ajouter les entêtes d’authentification à notre requête, ce qui n’est pas nécessaire sur l’explorateur comme les requêtes sont automatiquement authentifiées avec l’utilisateur courant.
La requête par défaut récupère via profile (profil de l’utilisateur courant) des informations précises (id, nickname, schoolYear, isFipa).
Le bouton rose ▶ (ou Ctrl+Enter) exécute la requête :

On reçoit alors la réponse en JSON à droite, de la forme demandée.
L’avantage majeur de GraphQL est son système de schéma, qui décrit l’entièreté des requêtes possibles ainsi que leur attributs. Le tout documenté avec des commentaires. En cliquant sur le libre à gauche vous pourrez parcourir le schéma.

D’autres requêtes sont possibles, par exemple sur groups en récupérant les données de façon paginée.

Utilisation des clients GraphQL
Vous pouvez effectuer des requêtes sur des données ARISE réelles à l’aide de divers clients et bibliothèques GraphQL.
Utilisation d’IDE clients GraphQL
Il existe de nombreux IDE clients GraphQL open source que vous pouvez utiliser pour accéder à l’API GraphQL d’ARISE.
Consultez la section Effectuer des appels avec GraphQL pour obtenir des informations détaillées sur les méthodes HTTP, l’authentification et la structure des appels GraphQL.
Commencez par choisir un client. Parmi les options courantes, on trouve GraphiQL, Insomnia et Altair (version bureau/web/extension). Vous pouvez consulter la liste complète des clients dans le répertoire des outils de l’organisation GraphQL.
Les instructions génériques suivantes fonctionnent avec la plupart des clients GraphQL :
- Pointez le client vers l’endpoint GraphQL : https://api.iiens.net/graphql/v1.
- Ajoutez un en-tête
Authorization:Authorization: Bearer TOKEN(remplacezTOKENpar votre jeton d’accès personnel ARISE. Pour plus d’informations, consultez la section Authentification avec un jeton d’accès personnel OAuth). - Définissez la méthode de requête sur
POSTou, si c’est possible, utilisez le mode GraphQL fourni par le client. - Saisissez votre requête ou votre mutation dans l’éditeur et, si nécessaire, fournissez des variables dans le panneau “Variables”. Exemple :
query {
profile {
id
}
}
- Si votre client nécessite d’un schéma pour le rendu de la documentation ou la saisie semi-automatique, récupérez-le via une requête d’introspection GraphQL. De nombreux clients peuvent le faire automatiquement à partir du panneau “Docs”. Requête d’introspection minimale :
query IntrospectionQuery {
__schema {
types {
name
}
}
}
- Exécutez la requête et examinez la réponse JSON. La requête de l’exemple devrait renvoyer l’identifiant associé au jeton d’accès personnel ARISE avec lequel vous vous êtes authentifié.
Utilisez l’interface utilisateur du client pour explorer la documentation, exécuter des requêtes et enregistrer des requêtes selon vos besoins.
Recommendations de clients par langage
Work In Progress
Utilisation de la pagination dans l’API GraphQL
Découvrez comment parcourir des ensembles de données à l’aide de la pagination par curseur avec l’API GraphQL.
À propos de la pagination
L’API GraphQL d’ARISE limite le nombre d’éléments que vous pouvez récupérer en
une seule requête afin de se prémunir contre les requêtes excessives ou abusives
adressées à nos serveurs. Lorsque vous utilisez l’API GraphQL, vous devez fournir
un argument first ou last pour chaque requête paginée. La valeur de ces
arguments doit être comprise entre 1 et 100. L’API GraphQL renverra le nombre
d’éléments spécifié par l’argument first ou last.
Si les données auxquelles vous accédez comportent plus de connexions que le
nombre d’éléments spécifié par l’argument first ou last, la réponse est
divisée en “pages” plus petites de la taille spécifiée. Ces pages peuvent être
récupérées une par une jusqu’à ce que l’ensemble des données ait été récupéré.
Chaque page contient le nombre d’éléments spécifié par l’argument first ou
last, sauf s’il s’agit de la dernière page, qui peut contenir un nombre
d’éléments inférieur.
Ce guide explique comment demander des pages supplémentaires de résultats pour les réponses paginées, comment modifier le nombre de résultats renvoyés sur chaque page et comment écrire un script pour récupérer plusieurs pages de résultats.
Tip
Le standard utilisé est le GraphQL Cursor Connections, créé par Relay. Bon nombre de clients GraphQL comprennent cette spécification et proposent des méthodes simplifiées pour itérer sur toutes les pages d’une requête.
Demander un curseur dans votre requête
Lorsque vous utilisez l’API GraphQL, vous utilisez des curseurs pour parcourir
un ensemble de données paginées. Le curseur représente une position spécifique
dans l’ensemble de données. Vous pouvez obtenir le premier et le dernier curseur
d’une page en interrogeant l’objet pageInfo. Par exemple :
query {
groups(first: 100, after: null) {
nodes {
id
name
createdAt
}
pageInfo {
endCursor
startCursor
hasNextPage
hasPreviousPage
}
}
}
Dans cet exemple, pageInfo.startCursor indique le curseur du premier élément
de la page. pageInfo.endCursor indique le curseur du dernier élément de la
page. pageInfo.hasNextPage et pageInfo.hasPreviousPage indiquent s’il existe
une page avant et après la page renvoyée.
Changer le nombre d’éléments par page
Les arguments first et last déterminent le nombre d’éléments renvoyés. Le
nombre maximal d’éléments que vous pouvez récupérer à l’aide de ces arguments
est de 100. Si votre requête porte sur un volume important de données, vous
devrez peut-être limiter le nombre d’éléments à moins de 100 afin d’éviter
d’atteindre une limite de débit ou une limite de nœuds. Pour plus d’informations,
consultez la section Limites pour l’API GraphQL.
Parcourir l’ensemble de données à l’aide de la pagination
Une fois que vous avez obtenu un curseur à la suite d’une requête, vous pouvez
l’utiliser pour demander la page suivante de résultats. Pour ce faire, utilisez
l’argument after ou before ainsi que le curseur.
Par exemple, en supposant que la valeur pageInfo.endCursor de l’exemple précédent
était InVybjp1dWlkOjAxOWNmMTJhLTRmMTAtNzExZi04MDRhLWY4ODg3Y2U3ZWRlMSI, vous
pouvez utiliser cette requête pour demander la page suivante de résultats :
query {
groups(first: 1, after: "InVybjp1dWlkOjAxOWNmMTJhLTRmMTAtNzExZi04MDRhLWY4ODg3Y2U3ZWRlMSI") {
nodes {
id
name
createdAt
}
pageInfo {
endCursor
hasNextPage
}
}
}
Vous pouvez continuer à envoyer des requêtes en utilisant la nouvelle valeur de
pageInfo.endCursor renvoyée dans la réponse jusqu’à ce qu’il n’y ait plus de
pages à parcourir, ce qui est indiqué par la valeur false renvoyée par
pageInfo.hasNextPage.
Important
Le contenu des curseurs doit être considéré comme opaque, il peut changer à tout moment. Il n’est donc pas recommandé de stocker les curseurs sur une longue période. Voir la spécification
Si vous avez spécifié l’argument last au lieu de first, la dernière page
de résultats sera renvoyée en premier. Dans ce cas, vous utiliserez la valeur
pageInfo.startCursor et l’argument before pour obtenir la page de résultats
précédente. Lorsque pageInfo.hasPreviousPage renvoie false, vous avez atteint
la dernière page. Par exemple :
query {
groups(last: 1, after: "InVybjp1dWlkOjAxOWNmMTJhLTRmMTAtNzExZi04MDRhLWY4ODg3Y2U3ZWRlMSI") {
nodes {
id
name
createdAt
}
pageInfo {
startCursor
hasPreviousPage
}
}
}
Référence
Cette section se concentre sur les spécificités de l’API.
Authentification
Vous pouvez vous authentifier auprès de l’API GraphQL à l’aide d’un jeton d’accès personnel OAuth, d’une application AriseID Connect ou d’un compte de service.
Authentification avec une application OAuth
Warning
AriseID Connect est encore en beta et cette section pourrait être amenée à changer.
Pour vous authentifier avec un jeton OAuth provenant d’une application AriseID Connect, vous devez d’abord autoriser votre application OAuth à l’aide d’un “Authorization Code Flow” ou d’un “Device Authorization Flow”. Vous pouvez ensuite utiliser le jeton d’accès (access token) que vous avez reçu pour accéder à l’API.
Les jeton d’accès (access token) s’utilisent avec une authentification bearer.
Authorization: Bearer <TOKEN>
Exemple avec cURL :
curl 'https://api.iiens.net/graphql/v1' \
-X POST \
-H 'Authorization: Bearer ory_at_JGhESDjKfHMQ8Wcy0cC3.hIQxGmX37ydn8WmKAnlD3U' \
-H 'content-type: application/json' \
--data '{
"query": "{ profile { id } }"
}'
Authentification avec un jeton d’accès personnel OAuth
Le Client Credentials Flow est utilisé lorsqu’une application doit accéder à ses propres ressources, plutôt qu’à celles d’un utilisateur. Dans ce flux, l’application envoie son identifiant client et sa clé secrète client au serveur d’autorisation, et reçoit en retour un jeton d’accès qui peut être utilisé pour accéder aux ressources protégées.
Warning
AriseID Connect est encore en beta et cette section pourrait être amenée à changer.
Pour vous authentifier avec un jeton d’accès personnel (personal access token ou “PAT”), suivez les étapes décrites dans la documentation AriseID Connect (TODO). Les données que vous demandez détermineront le scope ou les autorisations dont vous aurez besoin.
Par exemple, sélectionnez l’autorisation profile pour lire les données nécessaire pour afficher le profil de l’utilisateur.
Si votre jeton ne dispose pas du scope ou des autorisations requis pour accéder à une ressource, l’API renverra un message d’erreur indiquant que la requête ou le champ ne sont pas accessibles.
Authentification basique (client_secret_basic)
Cette méthode est appropriée pour les clients enregistrés en Token Endpoint Auth Method = client_secret_basic.
const clientID = "the-client-id"
const clientSecret = "the-secret-id"
const basicAuth = base64_encode(url_encode(clientID) + ":" + url_encode(clientSecret))
const requestOptions = {
method: "POST",
headers: {
Authorization: "Basic " + basicAuth,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials&scope=read",
}
fetch("https://oidc.iiens.net/oauth2/token", requestOptions)
.then((response) => response.json())
.then((data) => console.log(data))
Exemple d’output :
ory_at_JGhESDjKfHMQ8Wcy0cC3.hIQxGmX37ydn8WmKAnlD3U
Authentification dans le body (client_secret_post)
Cette méthode est appropriée pour les clients enregistrés en Token Endpoint Auth Method = client_secret_post.
const clientID = "the-client-id"
const clientSecret = "the-secret-id"
const qs = new URLSearchParams()
qs.set("grant_type", "client_credentials")
qs.set("client_id", clientID)
qs.set("client_secret", clientSecret)
qs.set("scope", read)
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: qs.toString(),
}
fetch("https://oidc.iiens.net/oauth2/token", requestOptions)
.then((response) => response.json())
.then((data) => console.log(data))
Exemple d’output :
ory_at_JGhESDjKfHMQ8Wcy0cC3.hIQxGmX37ydn8WmKAnlD3U
Requête avec le PAT
Une fois votre Personal Access Token obtenu, vous pouvez effectuer des requêtes à l’API.
Les PAT s’utilisent avec une authentification bearer.
Authorization: Bearer <TOKEN>
Exemple avec cURL :
curl 'https://api.iiens.net/graphql/v1' \
-X POST \
-H 'Authorization: Bearer ory_at_JGhESDjKfHMQ8Wcy0cC3.hIQxGmX37ydn8WmKAnlD3U' \
-H 'content-type: application/json' \
--data '{
"query": "{ profile { id } }"
}'
Authentification avec un compte de service
Les comptes de service ou “Service Account” permettent un accès plus large aux données, par exemple à l’ensemble des utilisateurs. Ces comptes sont utilisés en interne à ARISE mais peuvent aussi être délivrés aux utilisateurs ou associations qui en font la demande.
Caution
L’utilisation de ces jetons expose potentiellement des données sensibles. En utilisant un compte de service, vous vous engagez à respecter les normes RGPD et à protéger votre site par authentification.
Les jetons (tokens) de compte de service s’utilisent avec une authentification basique.
Authorization: Basic <TOKEN>
Exemple avec cURL :
curl 'https://api.iiens.net/graphql/v1' \
-X POST \
-H 'Authorization: Basic Y29tcHRlMTpsbCRWQmk2NTMjMExZeEEqaGFGJE13UDg=' \
-H 'content-type: application/json' \
--data '{
"query": "{ currentServiceAccount { id } }"
}'
Permissions
Par sécurité, aucune donnée n’est accessible sans être authentifié.
Données utilisateur
Liste des utilisateurs
En étant authentifié, les données accessibles sur les utilisateurs contiennent le nécessaire pour afficher un profil, sans données sensibles.
Important
Sont définis comme sensible :
- Le genre
- La photo de trombinoscope
- L’email
- Le numéro de téléphone
- Les réseaux sociaux
Profil personnel
Un utilisateur authentifié pourra accéder à ses propres données, y compris les données sensibles.
OAuth
Un utilisateur authentifié via OAuth ne verra aucune données utilisateur par défaut.
Warning
L’accès aux données des autres utilisateurs n’est pas possible avec OAuth.
L’accès aux données propres de l’utilisateur se fait via le système de scope, pour autoriser l’application à accéder à un sous ensemble de valeurs.
Liste non exhaustive de chaines valides :
profileemailgroups
Erreurs
Qu’est-ce qu’une erreur GraphQL ?
Lorsqu’un problème survient en GraphQL, le système ne s’arrête pas toujours complètement. Au lieu de cela, il renvoie :
- Certaines données (si possible) dans
data - Une section d’erreur expliquant ce qui n’a pas fonctionné dans
errors
Même si le statut HTTP est 200 OK, votre requête peut tout de même contenir des erreurs.
Les erreurs GraphQL comprennent :
message: une explication claire de ce qui a échoué.path: la partie de la requête qui a échoué.locations: la ligne et la colonne où le problème s’est produit.extensions: un objet structuré exploitable par une machine. Il contient toujours :code: un code décrivant le type d’erreur. La liste exhaustive est disponible plus bas.request_id: l’ID de la requête à fournir à ARISE lorsque l’erreur est un bug.
Important
Un code
5XXou4XXsignifie que le serveur web n’a pas pû traiter votre requête ou qu’elle n’est pas arrivée jusqu’au serveur GraphQL. Un code200signifie que la requête a été correctement traitée, mais pas forcément sans erreur !
Exemple de requête / réponse :
query {
profile {
id
}
}
{
"data": null,
"extensions": {
"analyzer": {
"complexity": 3,
"depth": 2
}
},
"errors": [
{
"message": "L'accès à la requête (profile) n'est pas autorisé avec les autorisations actuelles.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"profile"
],
"extensions": {
"code": "FORBIDDEN",
"query": "profile",
"request_id": "8fb550b6-cc63-469b-b4d7-40eb684c5a1c"
}
}
]
}
Erreurs client
UNAUTHENTICATED
Cause : La requête a fourni des identifiants invalides.
EXPIRED_CREDENTIALS
Cause : Les identifiants fournis ne sont plus valables.
Dans le cas d’identifiants OAuth (Bearer), il faut rafraîchir le jeton.
BAD_REQUEST
Cause : Le client a fourni des paramètres incorrects dans la requête.
| Paramètre | Optionnel | Description |
|---|---|---|
kind | Oui | Type d’erreur |
parameter | Oui | Le paramètre ayant causé l’erreur |
details | Oui | Détails de l’erreur sous forme texte |
Les types d’erreur possible sont :
TOO_MUCH_PAGINATION_ARGUMENTS
Une requête paginée doit avoir un paramètre first ou last mais ils sont
exclusifs.
NO_PAGINATION_LIMIT_PROVIDED
Une requête paginée doit avoir au minimum un paramètre first ou last.
INVALID_CURSOR
Le curseur fourni n’est pas reconnu. Le paramètre parameter spécifie quel
argument fourni a causé l’erreur.
NOT_FOUND
Note
Cette erreur n’est pas renvoyée par les requêtes de recherche d’une seule entité (
user,group, etc.). À la place, ces requêtes renvoientnullsi l’entité n’est pas trouvée.
Lorsqu’une entité est fournie en paramètre (ajout d’un role de groupe par exemple),
mais que cette entité n’existe pas dans le système alors NOT_FOUND est renvoyé.
| Paramètre | Description |
|---|---|
entity | Le type de l’entité introuvable |
urn | Son Uniform Resource Name, permettant de l’identifier |
CHECK_VIOLATION
Si une contrainte n’est pas respectée, cette exception est levée.
Si l’origine de l’erreur viens de la base de donnée, la table et constraint
seront spécifiés. Sinon, json_details expliquera l’origine de l’erreur.
| Paramètre | Optionnel | Description |
|---|---|---|
table | Oui | Table SQL concernée |
constraint | Oui | Contrainte impliquée dans l’erreur |
json_details | Oui | Détails de l’erreur sous forme JSON |
UNIQUE_VIOLATION
Cette erreur est provoquée par un conflit de base de donnée. Deux entitées possèdent les mêmes clés primaires ou un attribut unique est partagé.
| Paramètre | Description |
|---|---|
table | Table SQL concernée |
constraint | Contrainte impliquée dans l’erreur |
Erreurs serveur
INTERNAL_SERVER_ERROR
Important
Cette erreur signifie qu’un comportement imprévu est apparu au sein de l’API. Il s’agit certainement d’un bug, merci de contacter ARISE en fournissant le
request_id!
Erreurs internes
ID_GENERATION_FAILURE
Le compte utilisateur n’a pas pu être créé car la liste des ID valables est épuisée. Cela arrive généralement quand le nom de famille est très court et que plusieurs élèves portant ce nom de famille arrivent la même année.
| Paramètre | Description |
|---|---|
attempts | La liste des ID précédemment générés |
UNIX_UID_GENERATION_FAILURE
Le compte utilisateur n’a pas pu être créé car la liste des UID valables est épuisée.
| Paramètre | Description |
|---|---|
attempts | La liste des UID précédemment générés |
GLOBAL_STATE_ERROR
L’état global (table globals) des données est incohérent. Le paramètre kind
précise la source de l’erreur.
| Type | Description |
|---|---|
CURRENT_YEAR | L’année scolaire ne peut pas être mise à jour. L’année courante est déjà la bonne |
ODD_SEMESTER_STILL_ACTIVE | Le semestre pair ne peut être activé qu’à la nouvelle année civile |
Rate limits et limites de requêtes pour l’API GraphQL
L’API GraphQL d’ARISE est soumise à des restrictions visant à empêcher les appels excessifs ou abusifs vers nos serveurs.
Rate limits
Un rate limit représente une limitation du nombre de requête réalisable en un temps imparti.
Note
ARISE n’implémente actuellement pas de rate limit. Toutefois, en cas d’utilisation abusive de l’API, ARISE se réserve le droit d’imposer des sanctions.
Analyse d’une requête
Chaque requête est accompagnée d’une partie extensions et plus particulièrement
analyzer.
| Attribut | Limite | Description |
|---|---|---|
complexity | \(2048\) | Complexité totale de la requête, calculée en parcourant l’arbre syntaxique. Le coût est proportionnel au nombre direct d’attribut enfants, il est donc facile d’obtenir une complexité exponentielle. |
depth | \(16\) | Profondeur maximale de la requête |
Si une des deux limites est atteinte, la réponse sera :
{
"data": null,
"errors": [
{
"message": "Query is too complex."
}
]
}
Formule de complexité
Un champ simple aura pour complexité \( 0 \).
Toute requête faisant un appel en base de donnée aura pour complexité :
\[ Complexité_{défaut} = 3 \]
Tout attribut faisant un appel en base de donnée groupé (batch) aura pour complexité :
\[ Complexité_{batch} = Complexité_{défaut} + Complexité_{attribut} + 1 \]
Toute requête paginée d’une taille \( N \) aura pour complexité :
\[ Complexité_{pagination}(N) = Complexité_{défaut} + \sum_{i=0}^{N} (Complexité_{attribut_i} + 1) \]
Enfin, les requêtes non paginées mais retournant un nombre inconnu d’élément (par exemple, allPlatforms) auront pour complexité :
\[ Complexité_{inconnue} = 50 \]
Warning
La limite de complexité a pour but de limiter les usages abusifs et les dénis de service (DOS). ARISE se réserve le droit de changer le calcul de cette limite.
Exemple
query Profile {
profile {
id
nickname
schoolYear
isFipa: group(group: {id: "fisa"}) {
role {
value
}
}
}
}
profile = 3 + (
id = 0
nickname = 0
schoolYear = batch(1) = 3 + 1 + 1 = 5
group = batch(
role = 0 + (
value = 0
)
) = 3 + 0 + 1
)
Endpoints REST
L’API propose également certains endpoints REST en addition de GraphQL.
GET /_health
Cet endpoint renvoie toujours 200 OK. Une réponse différente indique que le
serveur web n’est pas accessible.
Tip
L’endpoint
/_readinessest préférable pour s’assurer que l’API est fonctionnelle
GET /_readiness
Cet endpoint vérifie que l’application est prête en envoyant une requête ping à la base de donnée afin de s’assurer que la connexion est active.
GET /photo/v1/{id}
Le champ photo du type User ne renvoie pas le contenu de la photo utilisateur
directement, mais une URL pointant sur cet endpoint.
Ces URLs sont signées et valides pour une durée de 1h. Elles peuvent donc être inclues dans une page web, tant que l’accès est authentifié.
Important
Il n’est pas possible d’appeler l’endpoint directement pour obtenir la photo d’un utilisateur. Il faut passer par le type
UserGraphQL pour obtenir une URL paramétrée.
Exemple d’URL :
https://api.iiens.net/photo/v1/mcfly1985?expires=1777071680&signature=ebd68c315e9810714c6ff648c55284ef999b15a96800dd5f1cba573def300b0a
GET /picture/v1/{id}
Cet endpoint est équivalent à /photo/v1/{id}, mais pour les images de profil
utilisateur.
Changelog
Tous les changements sur le schéma ou le fonctionnement de l’API sont répertoriés dans ce document. Les changements techniques sont décrit dans ce document.
Politique de versionnement
Les besoins évoluent au fil du temps, et GraphQL permet à une API de s’adapter à
ces besoins sans avoir à gérer différentes versions de l’API. Par exemple, si une
nouvelle fonctionnalité nécessite la mise à disposition de valeurs de nom plus
spécifiques, le type User pourrait être mis à jour comme suit :
type User {
fullName: String
nickname: String
name: String @deprecated(reason: "Utilisez `fullName`.")
}
Les outils client peuvent alors encourager les développeurs à utiliser les
nouveaux champs et à supprimer l’utilisation du champ name obsolète. Le champ
peut être supprimé une fois établi qu’il n’est plus utilisé ; en attendant,
GraphQL continuera à fournir ses données comme prévu.
Les API GraphQL ne sont usuellement pas versionnées. Cependant, ARISE a fait le
choix d’ajouter un préfixe /v1 à l’endpoint GraphQL. Malgré les mécanismes
décrit précédemment, il n’est pas simple de réussir le design d’une API du
premier coup. Le passage de la version 0 à la version 1 s’est déroulé avec
beaucoup de “breaking changes”, en maitrisant la version majeure nous avons pû
réaliser la transition en douceur.
Si un jour une réécriture complète de l’API est à prévoir, ce préfixe permettra à nouveau une transition plus douce pour les sites associatifs ou même ceux d’ARISE.
1.0.0 - 2026-04-12
Mise en production de l’API