Aller au contenu
Développement medium

Interagir avec des API REST en Python (Requests)

15 min de lecture

logo python

Les API REST sont aujourd’hui omniprésentes : services de géolocalisation, paiements en ligne, données météorologiques, réseaux sociaux… La capacité à communiquer avec ces interfaces depuis Python est devenue essentielle pour tout développeur. Qu’il s’agisse d’automatiser des processus métier, de récupérer des données externes ou d’intégrer des services tiers dans vos applications, les API REST constituent le pont qui relie votre code au monde extérieur. La bibliothèque requests de Python transforme cette communication en une tâche intuitive et élégante, permettant d’effectuer des requêtes HTTP complexes avec seulement quelques lignes de code.

Avant d’écrire la moindre ligne de code, il est essentiel de bien comprendre comment fonctionne une API REST. Ces interfaces permettent à des programmes d’échanger des données en s’appuyant sur le protocole HTTP, celui-là même qui fait fonctionner le web.

Une API REST expose des ressources (utilisateurs, machines, services…) accessibles via des endpoints (URL). Par exemple, l’URL suivante :

Fenêtre de terminal
https://api.exemple.com/v1/servers

peut renvoyer la liste des machines virtuelles disponibles sur une plateforme.

Chaque opération est liée à une méthode HTTP spécifique :

  • GET : lire des données
  • POST : créer une ressource
  • PUT : remplacer une ressource existante
  • PATCH : modifier partiellement une ressource
  • DELETE : supprimer une ressource

Ces méthodes sont utilisées pour décrire l’intention de l’appel.

La majorité des API REST échangent des données au format JSON, lisible et léger. Exemple de réponse :

{
"id": 42,
"name": "webserver-prod",
"status": "running"
}

À chaque appel, l’API renvoie un code de statut qui indique le résultat :

  • 200 OK : requête réussie
  • 201 Created : ressource créée
  • 204 No Content : suppression réussie, sans contenu
  • 400 Bad Request : syntaxe incorrecte
  • 401 Unauthorized : clé ou jeton manquant/invalide
  • 404 Not Found : ressource introuvable
  • 500 Internal Server Error : erreur côté serveur

Pour des raisons de sécurité, la majorité des API nécessitent une clé d’API ou un jeton Bearer :

Authorization: Bearer eyJhbGciOiJIUzI1...

Ces éléments doivent être transmis dans les headers HTTP, et ne jamais être codés en dur dans les scripts.

Plus d’informations sur les API REST

Avant de consommer des API REST en Python, il faut configurer un environnement propre, sécurisé et prêt pour l’automatisation. Voici les étapes à suivre.

Créez un environnement virtuel avec venv pour isoler vos dépendances :

Fenêtre de terminal
python -m venv venv
source venv/bin/activate

Le module requests est la bibliothèque la plus simple et la plus utilisée pour faire des appels HTTP en Python. Pour l’installer :

Fenêtre de terminal
pip install requests

Ce module gère les méthodes HTTP, les entêtes, les erreurs, l’encodage JSON, etc.

Organisez vos scripts avec une structure modulaire :

Fenêtre de terminal
mon_script_api/
├── main.py
├── api_utils.py
└── .env
  • main.py : point d’entrée du script
  • api_utils.py : fonctions réutilisables (authentification, requêtes)
  • .env : fichier contenant les clés d’API ou les jetons d’accès

Pour éviter de stocker des identifiants directement dans le code, stockez-les dans un fichier .env :

Fenêtre de terminal
API_KEY=sk_test_abc123
BASE_URL=https://api.exemple.com

Et lisez-les dans votre script avec la bibliothèque python-dotenv :

Fenêtre de terminal
pip install python-dotenv

Dans le script :

from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("API_KEY")

Pour éviter de commettre ce fichier dans Git, ajoutez .env à votre .gitignore.

La bibliothèque requests simplifie les appels HTTP en Python. Voici comment l’utiliser pour interagir avec une API REST.

Pour apprendre à l’utiliser, nous allons utiliser JSONPlaceholder. C’est une API REST factice gratuite qui simule des endpoints courants.

Pour récupérer une ressource, utilisez la méthode GET :

import requests
url = "https://jsonplaceholder.typicode.com/todos/1"
response = requests.get(url)
print(response.json())

Résultat attendu :

{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": False
}

Pour créer une nouvelle ressource, utilisez la méthode POST :

payload = {
"userId": 1,
"title": "Créer un playbook Ansible",
"completed": False
}
response = requests.post("https://jsonplaceholder.typicode.com/todos", json=payload)
print(response.json())

Même si la création est fictive, l’API renvoie un objet JSON contenant un ID simulé.

{
"userId": 1,
"title": "Créer un playbook Ansible",
"completed": False,
"id": 201
}

Pour remplacer une ressource existante, utilisez la méthode PUT :

update = {
"userId": 1,
"title": "Tâche mise à jour",
"completed": True
}
response = requests.put("https://jsonplaceholder.typicode.com/todos/1", json=update)
print(response.json())

Vous devriez obtenir une réponse similaire à celle-ci :

{
"userId": 1,
"id": 1,
"title": "Tâche mise à jour",
"completed": True
}

Pour modifier partiellement une ressource, utilisez la méthode PATCH :

partial = {"completed": False}
response = requests.patch("https://jsonplaceholder.typicode.com/todos/1", json=partial)
print(response.json())

La réponse contiendra uniquement les champs modifiés :

{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": False
}

Pour supprimer une ressource, utilisez la méthode DELETE :

response = requests.delete("https://jsonplaceholder.typicode.com/todos/1")
print(f"Code de statut : {response.status_code}")

En général, l’API renvoie un 204 No Content ou 200 OK sans contenu.

Lorsque vous consommez des API, il est essentiel de gérer les erreurs pour rendre vos scripts robustes, surtout dans un environnement d’infrastructure automatisé. Cela évite que des appels échoués passent inaperçus ou génèrent des comportements inattendus.

Chaque réponse d’API contient un code de statut HTTP. Utilisez-les pour détecter les erreurs :

response = requests.get("https://jsonplaceholder.typicode.com/todos/1")
if response.status_code == 200:
print("Succès :", response.json())
elif response.status_code == 404:
print("Ressource non trouvée.")
else:
print(f"Erreur : {response.status_code}")

Ou utilisez directement :

if response.ok:
# code 2xx

Cela est équivalente à vérifier si le code de statut est dans la plage 2xx.

Pour simplifier la détection, utilisez raise_for_status() :

try:
response = requests.get("https://api.exemple.com/data")
response.raise_for_status()
print(response.json())
except requests.exceptions.HTTPError as e:
print(f"Erreur HTTP : {e}")

Cette méthode déclenche une exception si le code HTTP n’est pas dans la plage 2xx.

Ici, le code lève une exception HTTPError si la requête échoue, ce qui permet de capturer les erreurs réseau ou de statut HTTP sans avoir à vérifier manuellement le code de statut.

Fenêtre de terminal
Erreur HTTP : 410 Client Error: Gone for url: https://api.exemple.com/data

Les problèmes de réseau ou d’URL incorrectes doivent être capturés avec RequestException :

try:
response = requests.get("https://mauvaise-url")
response.raise_for_status()
except requests.exceptions.ConnectionError:
print("Erreur de connexion")
except requests.exceptions.Timeout:
print("Délai d’attente dépassé")
except requests.exceptions.RequestException as e:
print(f"Erreur générale : {e}")

Ce code gère les erreurs de connexion, les délais d’attente et les autres exceptions liées aux requêtes.

Fenêtre de terminal
Erreur de connexion

Pour éviter que votre script ne reste bloqué en cas d’API lente :

requests.get("https://jsonplaceholder.typicode.com/todos/1", timeout=5)

Cela déclenche une exception après 5 secondes d’attente.

Dans un script d’automatisation, loguez les erreurs au lieu de juste les afficher :

import logging
logging.basicConfig(filename='api.log', level=logging.ERROR)
try:
r = requests.get("https://api.exemple.com/data")
r.raise_for_status()
except requests.exceptions.RequestException as e:
logging.error(f"Appel échoué : {e}")

Plus d’informations sur la gestion des erreurs.

Lorsqu’on consomme des API REST, la gestion de l’authentification est primordiale. Elle garantit que seules les entités autorisées peuvent accéder aux ressources. Python, via requests, permet de gérer plusieurs types d’authentification. Voici les modèles les plus courants, du plus simple au plus avancé.

Le schéma Basic envoie un couple utilisateur:motdepasse encodé en Base64 dans un entête HTTP :

Authorization: Basic base64(utilisateur:motdepasse)

Python gère automatiquement cette conversion via le module requests.auth :

from requests.auth import HTTPBasicAuth
import requests
auth = HTTPBasicAuth("admin", "motdepasse")
response = requests.get("https://api.exemple.com/serveurs", auth=auth)

Cela génère automatiquement le header :

Authorization: Basic YWRtaW46bW90ZGVwYXNzZQ==

⚠️ Cette méthode doit toujours être utilisée avec HTTPS, car l’encodage Base64 n’est pas du chiffrement.

De nombreuses APIs utilisent une clé d’authentification unique, transmise de deux façons :

headers = {
"x-api-key": "sk_test_ABC123"
}
response = requests.get("https://api.exemple.com/instances", headers=headers)
params = {
"api_key": "sk_test_ABC123"
}
response = requests.get("https://api.exemple.com/instances", params=params)

Ce type d’authentification est simple mais sensible à l’exposition de la clé. Elle donne un accès complet aux endpoints autorisés.

La méthode Bearer consiste à transmettre un jeton d’accès temporaire dans l’en-tête HTTP :

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

En Python :

headers = {
"Authorization": "Bearer VOTRE_JETON",
"Accept": "application/json"
}
response = requests.get("https://api.exemple.com/vms", headers=headers)

Ce jeton est souvent obtenu via un login initial ou une authentification OAuth2, et expire généralement après un certain temps.

De nombreuses APIs (GitLab, Azure, etc.) imposent un échange initial pour obtenir un jeton d’accès temporaire, en envoyant un client_id et un client_secret :

url = "https://auth.exemple.com/oauth/token"
data = {
"grant_type": "client_credentials",
"client_id": "votre_id",
"client_secret": "votre_secret"
}
response = requests.post(url, data=data)
access_token = response.json()["access_token"]

Puis utilisation du jeton :

headers = {"Authorization": f"Bearer {access_token}"}
requests.get("https://api.exemple.com/data", headers=headers)

Pour éviter de dupliquer les headers d’authentification sur plusieurs appels :

session = requests.Session()
session.headers.update({
"Authorization": "Bearer VOTRE_JETON",
"Accept": "application/json"
})
response = session.get("https://api.exemple.com/monitoring")

Cela améliore la lisibilité et la maintenabilité du code dans les scripts plus longs.

Bonnes pratiques pour sécuriser l’authentification API

Section intitulée « Bonnes pratiques pour sécuriser l’authentification API »

Utiliser une authentification sécurisée dans vos scripts Python ne suffit pas : il faut également adopter des bonnes pratiques pour éviter les fuites d’informations sensibles, protéger vos infrastructures, et garantir la maintenabilité de vos scripts d’automatisation.

Ne jamais coder en dur une clé ou un mot de passe

Section intitulée « Ne jamais coder en dur une clé ou un mot de passe »

Évitez d’insérer vos API keys, tokens, ou mots de passe directement dans le script. Exemple à éviter absolument :

# Mauvais exemple
headers = {"Authorization": "Bearer sk_live_tres_secret"}

En cas de fuite (GitHub, partage de fichier…), cela donne un accès direct à vos ressources.

Créez un fichier .env :

Fenêtre de terminal
API_KEY=sk_prod_xxxxxx
BEARER_TOKEN=eyJhbGciOiJIUzI1...

Ajoutez ensuite ce fichier à .gitignore :

Fenêtre de terminal
.env

Dans votre script Python, chargez les variables avec python-dotenv :

Fenêtre de terminal
pip install python-dotenv
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("API_KEY")
headers = {"x-api-key": api_key}

Tous les appels API doivent être faits sur des URLs HTTPS. Le chiffrement TLS :

  • Protège les données en transit (auth, payload)
  • Évite les attaques de type man-in-the-middle

Stocker les logs d’erreurs sans exposer les secrets

Section intitulée « Stocker les logs d’erreurs sans exposer les secrets »

Lorsque vous tracez des appels API échoués, n’incluez jamais les clés ou tokens dans les logs :

import logging
try:
response = requests.get("https://api.exemple.com/infra")
response.raise_for_status()
except requests.exceptions.RequestException as e:
logging.error(f"Erreur API : {e}")
  • Toujours ajouter .env à .gitignore
  • Scanner votre historique Git avec truffleHog ou gitleaks pour détecter les fuites
  • Utiliser GitHub Secrets, GitLab CI/CD Variables ou Vault pour injecter les valeurs dynamiquement

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80%

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Consommer des API REST en Python est une compétence indispensable pour automatiser et intégrer vos outils d’infrastructure. Grâce à la simplicité de requests, il est possible de piloter des services distants de manière fiable et sécurisée. En appliquant les bonnes pratiques d’authentification et de gestion des erreurs, vos scripts deviennent des briques robustes au cœur de vos workflows DevOps.