API GitLab et webhook : token, pagination, alerte
Appeler une API authentifiée avec un token placé dans un en-tête et lu dans os.environ, récupérer toutes les pages d'une liste, nettoyer un nom avec removeprefix, puis envoyer une alerte utile sur un webhook avec requests.post.
Mis à jour le
À recouper avec le cours. Cette leçon a été écrite à partir du plan du chapitre, avant relecture avec les supports. En cas de doute, le cours fait foi.
Pourquoi on voit ça
L’outil sait maintenant dire si un serveur est ok, degraded ou down. Il lui manque deux choses pour être utile en équipe :
- lire des informations ailleurs : par exemple la liste des projets dans GitLab, grâce à son API ;
- prévenir quelqu’un : poster une alerte dans le salon de l’équipe, grâce à un webhook.
Dans les deux cas, on manipule un secret. Cette leçon montre où le mettre, et surtout où ne pas le mettre.
Appeler une API authentifiée
Une API comme celle de GitLab ne répond pas à n’importe qui : elle veut savoir qui demande. On lui présente un token, une longue chaîne qui joue le rôle de mot de passe.
Le token : dans un en-tête, lu dans os.environ
Deux règles.
1. La valeur du token vient de l’environnement. On la lit avec os.environ, jamais on ne l’écrit dans le script.
import os
token = os.environ["GITLAB_TOKEN"]
Si la variable manque, les crochets lèvent KeyError : sans token, l’outil ne peut rien faire, autant s’arrêter tout de suite.
2. Le token voyage dans un en-tête. Pour GitLab, l’en-tête s’appelle PRIVATE-TOKEN.
import os
import requests
s = requests.Session()
s.headers.update({"PRIVATE-TOKEN": os.environ["GITLAB_TOKEN"]})
r = s.get("https://gitlab.example.com/api/v4/projects", timeout=5)
r.raise_for_status()
print(len(r.json()))
20
Pourquoi ces deux règles ?
| Endroit | Problème |
|---|---|
| dans le code | le script part dans Git : toute personne qui lit le dépôt lit le token |
| dans l’URL | les adresses sont enregistrées dans les journaux des serveurs et s’affichent dans les messages d’erreur |
dans un en-tête, lu dans os.environ |
le token n’est ni dans le dépôt, ni dans l’adresse |
Le traceback de raise_for_status() affiche l’URL complète. Si le token y était, il s’étalerait dans les logs.
La pagination
Dans l’exemple, la réponse contient 20 projets, alors qu’il y en a peut-être 250. Une API ne renvoie jamais une longue liste d’un seul coup : elle la découpe en pages.
Deux paramètres règlent ce découpage :
| Paramètre | Sens |
|---|---|
page |
le numéro de la page voulue, à partir de 1 |
per_page |
le nombre de résultats par page |
On les passe avec params= : requests les ajoute à la fin de l’adresse (?page=1&per_page=100).
Pour tout récupérer, on boucle tant qu’une page renvoie des résultats :
url = "https://gitlab.example.com/api/v4/projects"
projets = []
page = 1
while True:
r = s.get(url, params={"page": page, "per_page": 100}, timeout=5)
r.raise_for_status()
lot = r.json()
if not lot:
break
projets.extend(lot)
page = page + 1
print(len(projets), "projets")
250 projets
À lire dans ce code :
lotest une liste. Une liste vide compte comme faux :if not lotsignifie « si la page est vide ».projets.extend(lot)ajoute tous les éléments delotà la fin deprojets.page = page + 1: sans cette ligne, on redemanderait la page 1 sans fin.
Avec 250 projets et per_page=100 :
| Requête | page |
Résultats reçus | Suite |
|---|---|---|---|
| 1 | 1 | 100 | on continue |
| 2 | 2 | 100 | on continue |
| 3 | 3 | 50 | on continue |
| 4 | 4 | 0 | page vide : break |
Il faut donc quatre requêtes : c’est la page vide qui annonce la fin.
str.removeprefix
Les noms rendus par une API portent souvent un début dont on ne veut pas : le groupe devant le nom d’un projet, refs/heads/ devant le nom d’une branche. removeprefix retire ce début s’il est présent.
nom = "infra/fleetcheck"
print(nom.removeprefix("infra/"))
print(nom.removeprefix("ops/"))
print(nom)
fleetcheck
infra/fleetcheck
infra/fleetcheck
Trois choses à voir :
- le préfixe est là : il est retiré ;
- le préfixe n’est pas là : la chaîne est rendue telle quelle, sans erreur ;
- comme toutes les méthodes de
str,removeprefixrenvoie une chaîne neuve.nomn’a pas changé. Pour garder le résultat :nom = nom.removeprefix("infra/").
Le webhook : envoyer l’alerte
Un webhook est une adresse fournie par un outil de discussion. Tout ce qu’on y envoie s’affiche comme un message dans un salon.
Jusqu’ici, on lisait avec GET. Pour envoyer des données, on utilise la méthode POST :
import os
import requests
alerte = {"text": "web-2 (prod) est down : HTTP 503 sur /health depuis 14:32"}
r = requests.post(os.environ["WEBHOOK_URL"], json=alerte, timeout=5)
r.raise_for_status()
Le paramètre json= reçoit un dictionnaire Python. requests le convertit en JSON, le place dans le corps de la requête et prévient le serveur que c’est du JSON. Le nom de la clé (text ici) dépend de l’outil de discussion.
Le reste ne change pas : toujours un timeout=, et raise_for_status() pour savoir si l’alerte est bien partie.
Une alerte utile : quoi, où, depuis quand
Une alerte est lue par quelqu’un qui doit décider vite. Elle répond à trois questions.
| Question | Dans l’exemple |
|---|---|
| Quoi ? | est down, HTTP 503 |
| Où ? | web-2, en prod, sur /health |
| Depuis quand ? | 14:32 |
L’URL du webhook est un secret
Un webhook ne demande ni token ni mot de passe : connaître l’URL suffit pour poster. L’adresse est à elle seule la clé du salon.
Si elle fuit, n’importe qui peut envoyer de fausses alertes à l’équipe ou noyer les vraies. On la traite donc comme un token : lue dans os.environ, jamais écrite dans le code, jamais dans Git, jamais affichée dans un log.
À retenir
- Le token se lit dans
os.environet voyage dans un en-tête (PRIVATE-TOKENpour GitLab). Jamais dans l’URL, jamais dans le code. - Pagination : paramètres
pageetper_page. On boucle tant qu’une page renvoie des résultats ; la page vide arrête la boucle. s.removeprefix("x")retire le début s’il est présent, sinon rend la chaîne telle quelle. L’originale ne change pas.requests.post(url, json=dico, timeout=5)envoie le dictionnaire en JSON dans le corps de la requête.- Une alerte utile dit quoi, où, depuis quand.
- L’URL d’un webhook est un secret : qui la connaît peut poster.
Entraînement
12 questions, dont 4 à compléter. Tu réponds, on passe à la suivante. La note arrive à la fin.
Ta note
Cartes · 7
Réviser les cartes ici
Pourquoi