Consommer une API réseau
Définition
Consommer une API réseau, c'est piloter un équipement ou un contrôleur par ses interfaces HTTP plutôt que par sa CLI : envoyer une requête (curl, Postman, script Python), lire la réponse structurée, et enchaîner les appels dans un automate. La compétence testée n'est pas le protocole lui-même mais le geste : bonne URL, bons en-têtes, bonne authentification, parsing propre du JSON reçu.
Contexte
Le blueprint 200-301 v1.1, topics 6.5 et 6.9, attend que le candidat reconnaisse les composants d'un appel API : URL, verbe, en-têtes, payload, code de retour, et sache lire un extrait de script Python qui consomme une API. Les questions montrent souvent un bloc curl ou requests à interpréter, pas à écrire de mémoire. La bonne pratique « API plutôt que screen scraping CLI » (topic 6.1) tombe dans le même panier.
Premier appel : curl
curl est le client HTTP de référence pour tester une API depuis un terminal. Sur un équipement IOS XE avec certificat auto-signé et compte local, l'appel complet de lecture d'interface :
curl -k -u admin:MaSecret1! \
-H "Accept: application/yang-data+json" \
https://198.51.100.5/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet1/state
Trois options à savoir lire : -k ignore le certificat auto-signé (utile en lab, jamais en production sans PKI interne), -u user:pass active l'authentification Basic, -H injecte un en-tête. L'écriture d'une configuration se fait en POST ou PATCH avec un corps JSON via -d, et l'option -X force le verbe si curl ne le déduit pas :
curl -k -u admin:MaSecret1! -X PUT \
-H "Content-Type: application/yang-data+json" \
-d '{"ietf-interfaces:interface": {"name": "GigabitEthernet2", "description": "Vers distribution", "enabled": true}}' \
https://198.51.100.5/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2
L'API publique Meraki se consomme pareil, avec une clé d'organisation dans l'URL et l'en-tête d'authentification porteur :
curl -X GET "https://api.meraki.com/api/v1/organizations" \
-H "X-Cisco-Meraki-API-Key: <cle>" \
-H "Accept: application/json"
En Python : requests et parsing
La bibliothèque tierce requests encapsule l'appel, la réponse se convertit en dictionnaire par .json() (équivalent de json.loads sur le corps). Le contrôle du code de statut se fait par response.status_code ou raise_for_status() :
import requests
from requests.auth import HTTPBasicAuth
base = "https://198.51.100.5/restconf/data"
headers = {"Accept": "application/yang-data+json"}
auth = HTTPBasicAuth("admin", "MaSecret1!")
resp = requests.get(
f"{base}/ietf-interfaces:interfaces",
auth=auth, headers=headers, verify=False,
)
resp.raise_for_status() # leve une erreur si 4xx/5xx
data = resp.json() # corps JSON -> dict Python
for intf in data["ietf-interfaces:interface"]:
name = intf["name"]
eth = intf.get("state", {}).get("ethernet", {})
print(name, intf["state"]["oper-status"], eth.get("mtu"))
Le pattern d'écriture équivalent : requests.patch(url, json=payload, auth=auth, headers=h) ; le paramètre json= sérialise le dictionnaire et pose Content-Type automatiquement, une source fréquente de questions : quand un script « marche » sans en-tête explicite, c'est que la bibliothèque l'a ajouté pour lui. Noter verify=False en lab, et get() avec valeur par défaut pour les noeuds optionnels du modèle : une clé absente dans la réponse lèverait un KeyError sinon.
Rate limiting et limites
Toute API impose un débit maximal. Un serveur qui sature répond 429 Too Many Requests, souvent avec l'en-tête Retry-After indiquant combien de secondes attendre. Les politiques typiques : un nombre de requêtes par seconde et par compte, un budget de points par heure. Les bonnes pratiques : lire la limite dans les en-têtes de réponse (type X-RateLimit-Remaining selon l'API), espacer les appels (file à 5 fils plutôt que 60 parallèles), backoff exponentiel sur 429 (attendre 1 s, 2 s, 4 s), mettre en cache les lectures qui n'ont pas besoin d'être fraîches. Un script qui boucle sans contrôle sur 200 devices déclenchera l'anti-DDoS interne avant la fin de l'inventaire.
API plutôt que CLI
Le topic 6.1 pose la comparaison : scraper une sortie CLI (show version | include) oblige à parser du texte libre, dont chaque version d'OS change un espace ou un libellé, alors qu'une API renvoie du JSON typé par un modèle, stable et documenté. Les règles de l'art : ne pas scripter en SSH/expect ce qu'une API officielle expose déjà ; conserver les identifiants dans des variables d'environnement et non en dur dans le dépôt ; journaliser les codes de retour pour auditer les campagnes ; tester en lab avant la production, sur une URL de sandbox quand l'éditeur en fournit une.
Exemple concret chiffré
Campagne de relevé MTU sur 150 switchs. Version CLI expect : 22 s par device (setup SSH, prompt, paging), 55 minutes séquentielles, 11 échecs de parsing dans la semaine à cause d'une ligne show interface coupée par le terminal-length. Version RESTCONF en requests avec une Pool de 10 fils : 0,9 s par GET, 150 appels en 14 secondes, 0 échec de parsing ; trois 429 reçus pendant le run, absorbés par un retry à 2 s d'attente. Écart de temps de campagne : un facteur 235, mais surtout un écart de maintenance : le script CLI consommait 3 à 4 heures de correction par montée de version IOS, le script API zéro puisque le schéma YANG ne bouge pas.