Formats de données & Export
Les analystes et outils de BI ont souvent besoin d'exporter les données en CSV pour les exploiter dans Excel, pandas ou d'autres outils. L'API doit donc servir plusieurs formats.
JSON : le format par défaut
JSON (JavaScript Object Notation) est le format standard des APIs web :
{
"data": [
{"id": 1, "region": "IDF", "montant": 1500.0, "date": "2024-03-15"},
{"id": 2, "region": "PACA", "montant": 2300.0, "date": "2024-03-14"}
],
"total": 15420,
"limit": 20,
"offset": 0
}
Avantages : structuré (objets imbriqués), typé (nombres, chaînes, booléens), standard des APIs.
Limites : plus volumineux que le CSV pour de grandes quantités de données tabulaires, moins pratique pour l'import dans Excel.
CSV : le format d'export
Le CSV (Comma-Separated Values) est un format tabulaire, directement ouvrable dans Excel ou importable dans pandas :
id,region,montant,date
1,IDF,1500.0,2024-03-15
2,PACA,2300.0,2024-03-14
Implémentation Flask
import csv
import io
from flask import Response
@ventes_bp.route('/export', methods=['GET'])
def exporter_ventes():
"""Exporte les ventes filtrées en CSV."""
region = request.args.get('region')
annee = request.args.get('annee', type=int)
# Récupérer toutes les données (sans pagination pour l'export)
ventes = repository.find_all_for_export(region=region, annee=annee)
# Générer le CSV en mémoire
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=['id', 'region', 'montant', 'date', 'categorie'])
writer.writeheader()
writer.writerows(ventes)
# Retourner comme fichier téléchargeable
return Response(
output.getvalue(),
mimetype='text/csv',
headers={
'Content-Disposition': 'attachment; filename=ventes_export.csv'
}
)
Content-Disposition
Le header Content-Disposition: attachment; filename=ventes_export.csv indique au navigateur de télécharger le fichier au lieu de l'afficher. Le nom de fichier suggéré est ventes_export.csv.
Export avec filtres dans le nom de fichier
Pour que le fichier exporté soit identifiable, on peut inclure les filtres dans le nom :
# Nom de fichier dynamique
parts = ['ventes']
if region:
parts.append(region)
if annee:
parts.append(str(annee))
filename = '_'.join(parts) + '.csv'
# Résultat : ventes_IDF_2024.csv
Un endpoint, deux formats
Plutôt que de créer un endpoint séparé /export, on peut utiliser un query parameter pour choisir le format :
GET /api/v1/ventes?format=json # Réponse JSON (défaut)
GET /api/v1/ventes?format=csv # Téléchargement CSV
@ventes_bp.route('', methods=['GET'])
def lister_ventes():
format_sortie = request.args.get('format', 'json')
# Récupérer les données (filtres, pagination, etc.)
# ...
if format_sortie == 'csv':
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=['id', 'region', 'montant', 'date'])
writer.writeheader()
writer.writerows(ventes)
return Response(
output.getvalue(),
mimetype='text/csv',
headers={'Content-Disposition': 'attachment; filename=ventes.csv'}
)
# Format JSON par défaut
return jsonify({
"data": ventes,
"total": total,
"limit": limit,
"offset": offset,
})
Pagination et export CSV
Attention : pour un export CSV, on veut généralement toutes les données (pas de pagination). Vous pouvez soit ignorer limit/offset quand format=csv, soit plafonner à une limite raisonnable (ex : 50 000 lignes) pour protéger le serveur.
Négociation de contenu avec le header Accept
Une autre approche utilise le header HTTP Accept :
# Demander du JSON
curl -H "Accept: application/json" http://localhost:5000/api/v1/ventes
# Demander du CSV
curl -H "Accept: text/csv" http://localhost:5000/api/v1/ventes
@ventes_bp.route('', methods=['GET'])
def lister_ventes():
# Vérifier le header Accept
if request.accept_mimetypes.best == 'text/csv':
# Retourner en CSV
...
else:
# Retourner en JSON (défaut)
...
En pratique, le query parameter ?format=csv est plus explicite, surtout quand l'API est consommée par des scripts qui ne manipulent pas facilement les headers.
Quel header HTTP indique au navigateur de télécharger la réponse comme fichier ?
À retenir
Points clés
- JSON est le format par défaut des APIs web
- CSV sert à l'export vers Excel, pandas et les outils de BI
- Utilisez
Content-Disposition: attachmentpour déclencher le téléchargement - Le query parameter
?format=csvest l'approche la plus simple pour proposer les deux formats - Pour l'export CSV, désactivez la pagination ou augmentez la limite maximale
- Le module Python
csv.DictWritersimplifie la génération de CSV à partir de dictionnaires