Qu'est-ce qu'une API et que signifie « extraire des données via une API »
API (Application Programming Interface) désigne une interface par laquelle un programme s'adresse à un autre pour obtenir des données ou déclencher des actions, sans connaître son fonctionnement interne. En pratique, « travailler avec une API » signifie le plus souvent interroger une API web via le protocole HTTP : le client envoie une requête à une adresse donnée (endpoint), et le serveur renvoie une réponse.
Par « extraction de données via API », on entend l'ensemble du cycle de récupération et d'analyse des données d'un service externe :
- Construire et envoyer une requête HTTP correcte.
- Recevoir la réponse du serveur.
- Vérifier le statut de la réponse et les en-têtes.
- Analyser le corps de la réponse (le plus souvent du JSON) pour le convertir en objets du programme.
- Gérer les erreurs, les nouvelles tentatives et la pagination.
Voir aussi : l'article « Parsing de JSON » est consacré à l'étape précise d'analyse des données elles-mêmes — la transformation d'une chaîne JSON en objets. Le présent article couvre l'ensemble du processus de travail avec une API, dont cette analyse fait partie.
Contrairement au « scraping de sites » (extraction de HTML), le travail avec une API s'appuie sur des réponses structurées dans un format lisible par machine : il est donc plus fiable, plus stable et presque toujours préférable lorsque le service dispose d'une API officielle.
Anatomie d'une requête HTTP
Toute requête vers une API web se compose de plusieurs éléments.
La méthode (verbe HTTP)
La méthode décrit l'intention de la requête :
- GET — obtenir des données (ne modifie pas l'état).
- POST — créer une nouvelle ressource ou envoyer des données.
- PUT / PATCH — mettre à jour une ressource (entièrement / partiellement).
- DELETE — supprimer une ressource.
URL et paramètres de requête
L'adresse de l'endpoint peut contenir des paramètres de requête (query) pour le filtrage, le tri et la pagination :
https://api.example.com/users?role=admin&page=2&limit=50
Les en-têtes (headers)
Les en-têtes transmettent les métadonnées de la requête. Les plus importants pour le travail avec une API :
Authorization— données d'authentification (token, clé).Content-Type— format du corps envoyé (par exemple,application/json).Accept— format dans lequel le client souhaite recevoir la réponse.User-Agent— identifiant du client.
Le corps de la requête (body)
Pour POST/PUT/PATCH, les données sont transmises dans le corps — en général sous forme de chaîne JSON, qu'il faut au préalable sérialiser à partir des objets du programme.
Anatomie de la réponse et son analyse
La réponse du serveur se compose d'un code de statut, d'en-têtes et d'un corps.
Les codes de statut
Avant d'analyser le corps, il faut vérifier le code de statut :
- 2xx — succès (
200 OK,201 Created,204 No Content). - 3xx — redirection.
- 4xx — erreur côté client (
400requête invalide,401non authentifié,403accès interdit,404introuvable,429trop de requêtes). - 5xx — erreur côté serveur.
Analyser le corps comme des données valides n'a de sens qu'avec un code 2xx. Le corps d'une erreur contient d'ailleurs souvent un JSON utile décrivant le problème.
Les en-têtes de réponse
Les en-têtes de réponse fournissent des informations importantes : Content-Type (format du corps), paramètres de pagination, limites de requêtes (X-RateLimit-Remaining), gestion du cache.
Le corps de la réponse
Le corps contient les données elles-mêmes. Dans la plupart des API, il s'agit de JSON qu'il faut parser (voir « Parsing de JSON »). Plus rarement, on rencontre d'autres formats texte — XML (voir « Parsing de XML ») et CSV (voir « Parsing de CSV ») — ainsi que des formats binaires.
Authentification et autorisation
La plupart des API exigent de prouver que le client a le droit d'y accéder. Les méthodes les plus courantes :
- Clé d'API — une simple chaîne, transmise dans un en-tête ou un paramètre de requête.
- Token Bearer / OAuth 2.0 — un token dans l'en-tête
Authorization: Bearer <token>; l'approche la plus répandue dans les API modernes. - Basic Auth — identifiant et mot de passe sous forme encodée.
- HMAC / signature de requête — la requête est signée avec un secret ; utilisé dans les API de paiement et de cloud.
Important : les clés et les tokens sont des secrets. Il ne faut jamais les stocker dans le code ni les commiter dans un dépôt ; utilisez des variables d'environnement ou des coffres-forts sécurisés.
Les difficultés du travail avec les API
L'extraction via API se résume rarement à une seule requête. Voici les difficultés typiques auxquelles il faut se préparer.
La pagination
Une API ne renvoie presque jamais de grandes collections en une seule fois — les données sont découpées en pages. Les principaux modèles :
- Offset/limit —
?page=2&limit=50ou?offset=100&limit=50. - Par curseur (cursor) — la réponse contient un pointeur vers la page suivante (
next_cursor), transmis dans la requête suivante. - Keyset — la page suivante est demandée à partir de la valeur du dernier élément (par exemple, l'
idou la date).
Pour collecter toutes les données, il faut une boucle qui parcourt les pages jusqu'à épuisement.
La limitation du débit de requêtes (rate limiting)
Les services limitent le nombre de requêtes par période. En cas de dépassement, on reçoit le code 429. La bonne approche consiste à surveiller les en-têtes de limites et à appliquer un délai exponentiel (backoff) avec de nouvelles tentatives.
L'instabilité du réseau et les nouvelles tentatives
Les requêtes réseau peuvent échouer par timeout ou à cause d'erreurs 5xx temporaires. Pour la robustesse, on applique :
- des timeouts raisonnables ;
- des nouvelles tentatives (retry) pour les requêtes idempotentes, avec délai croissant ;
- le patron circuit breaker en cas de défaillances systématiques.
La variabilité et la validation des données
La réponse d'une API peut arriver incomplète, avec des champs null ou une structure modifiée après une mise à jour de version de l'API. Il ne faut jamais faire aveuglément confiance à la structure de la réponse — les champs doivent être vérifiés et les données validées.
Le versionnage
Les API évoluent et leurs versions changent (/v1/, /v2/). Il est recommandé de figer une version précise et de suivre les annonces de dépréciation (deprecation).
L'imbrication et les formats variés
Les données utiles sont souvent enfouies profondément dans une structure imbriquée (data.items[0].attributes.name). Parfois, au lieu de JSON, on reçoit du XML (voir « Parsing de XML ») ou du CSV (voir « Parsing de CSV »), ce qui exige un autre parseur.
Exemples d'implémentation dans différents langages
Voici des exemples minimaux du cycle complet : requête vers l'API, vérification du statut et analyse de la réponse JSON. Pour l'uniformité, on utilise un endpoint fictif https://api.example.com/users/42.
Python
La bibliothèque populaire requests prend en charge à la fois la requête et l'analyse du JSON.
import requests
url = "https://api.example.com/users/42"
headers = {"Authorization": "Bearer YOUR_TOKEN"}
response = requests.get(url, headers=headers, timeout=10)
# Vérification du statut
response.raise_for_status() # lève une exception en cas de 4xx/5xx
# Analyse de la réponse JSON en dictionnaire
user = response.json()
print(user["name"])
Exemple de collecte de toutes les pages (offset/limit) :
def fetch_all_users():
users, page = [], 1
while True:
resp = requests.get(
"https://api.example.com/users",
params={"page": page, "limit": 50},
timeout=10,
)
resp.raise_for_status()
batch = resp.json()["data"]
if not batch:
break
users.extend(batch)
page += 1
return users
JavaScript (Node.js / navigateur)
Le fetch intégré renvoie une promesse ; l'analyse du JSON se fait avec la méthode .json().
const url = "https://api.example.com/users/42";
const response = await fetch(url, {
headers: { Authorization: "Bearer YOUR_TOKEN" },
});
// Vérification du statut
if (!response.ok) {
throw new Error(`Erreur API : ${response.status}`);
}
// Analyse du JSON
const user = await response.json();
console.log(user.name);
Exemple d'envoi de données (POST) :
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_TOKEN",
},
body: JSON.stringify({ name: "Anna", role: "admin" }), // sérialisation
});
const created = await response.json();
Java
Java moderne intègre un HttpClient ; pour l'analyse du JSON, on utilise une bibliothèque (ici, Jackson).
import java.net.URI;
import java.net.http.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
public class ApiExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users/42"))
.header("Authorization", "Bearer YOUR_TOKEN")
.GET()
.build();
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Erreur API : " + response.statusCode());
}
ObjectMapper mapper = new ObjectMapper();
JsonNode user = mapper.readTree(response.body());
System.out.println(user.get("name").asText());
}
}
Go
La bibliothèque standard fournit à la fois un client HTTP (net/http) et un parseur (encoding/json).
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type User struct {
Name string `json:"name"`
}
func main() {
req, _ := http.NewRequest("GET", "https://api.example.com/users/42", nil)
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
panic(fmt.Sprintf("Erreur API : %d", resp.StatusCode))
}
var user User
json.NewDecoder(resp.Body).Decode(&user) // analyse du corps en flux
fmt.Println(user.Name)
}
C
Dans .NET, on utilise HttpClient et le System.Text.Json intégré.
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
record User(string Name);
class Program
{
static async Task Main()
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_TOKEN");
var response = await client.GetAsync("https://api.example.com/users/42");
response.EnsureSuccessStatusCode();
// Analyse du JSON directement en objet typé
var user = await response.Content.ReadFromJsonAsync<User>();
Console.WriteLine(user?.Name);
}
}
PHP
La requête se fait avec cURL, et json_decode analyse la réponse.
<?php
$ch = curl_init("https://api.example.com/users/42");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_TOKEN"]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
throw new Exception("Erreur API : $status");
}
// Analyse du JSON en tableau associatif
$user = json_decode($body, true);
echo $user["name"];
Rust
La combinaison populaire : le client asynchrone reqwest et serde pour l'analyse.
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
name: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let response = client
.get("https://api.example.com/users/42")
.header("Authorization", "Bearer YOUR_TOKEN")
.send()
.await?;
if !response.status().is_success() {
return Err(format!("Erreur API : {}", response.status()).into());
}
// Analyse du JSON en structure
let user: User = response.json().await?;
println!("{}", user.name);
Ok(())
}
Comparaison des outils
| Langage | Client HTTP | Analyse du JSON |
|---|---|---|
| Python | requests / httpx |
.json() (json) |
| JavaScript | fetch / axios |
.json() (JSON) |
| Java | HttpClient |
Jackson / Gson |
| Go | net/http |
encoding/json |
| C# | HttpClient |
System.Text.Json |
| PHP | cURL / Guzzle | json_decode |
| Rust | reqwest |
serde / serde_json |
Bonnes pratiques
Pour construire un travail fiable avec les API, il convient de respecter quelques principes :
- Vérifiez toujours le code de statut avant d'analyser le corps de la réponse.
- Encapsulez l'analyse dans une gestion d'erreurs — les données externes ne sont pas fiables.
- Ne stockez pas de secrets dans le code — utilisez des variables d'environnement.
- Respectez les limites de requêtes — appliquez des délais et un backoff en cas de 429.
- Définissez des timeouts sur chaque requête pour éviter les blocages.
- Journalisez les requêtes et les erreurs — cela simplifie le débogage des intégrations.
- Mettez en cache les données qui changent rarement, afin de réduire la charge et de ne pas buter sur les limites.
- Figez la version de l'API et suivez les annonces de dépréciation.
- Validez la structure de la réponse avant d'utiliser les champs.
Conclusion
L'extraction de données via API, c'est le cycle complet d'interaction avec un service externe : construction de la requête, authentification, vérification du statut et des en-têtes, analyse du corps de la réponse et gestion des cas limites — pagination, limites de débit, pannes réseau. Techniquement, l'étape d'analyse des données se résume presque toujours au parsing de JSON, mais une intégration robuste exige de prendre en compte tout ce qui l'entoure.
Des outils existent dans chaque langage courant : parfois le client HTTP et le parseur sont intégrés, parfois on utilise des bibliothèques populaires. Le principe reste partout le même — transformer la réponse d'un service distant en données fiables avec lesquelles on peut travailler en toute sécurité dans le code.
Pour en savoir plus sur l'étape d'analyse des données elle-même, consultez l'article « Parsing de JSON », et sur l'analyse des autres formats de réponse — les articles « Parsing de XML » et « Parsing de CSV ».