Structure d’une API Flask
Flask est ce que l’on appelle un micro-framework. Cela signifie qu’il fournit uniquement l’essentiel pour créer une application web ou une API, mais laisse beaucoup de liberté sur la manière de structurer votre projet. Contrairement à un framework complet comme Django, Flask ne dicte pas où mettre vos fichiers ou comment organiser votre logique métier. Cette liberté est double : elle permet une grande flexibilité, mais sans bonnes pratiques, le code peut rapidement devenir difficile à maintenir.
Une API bien structurée n’est pas seulement plus jolie sur le papier : elle est plus fiable, plus facile à tester, et plus compréhensible pour une équipe de développement. Pour un data scientist, cela devient crucial lorsqu’une API sert à exposer des modèles de machine learning, car des choix d’architecture mal pensés peuvent entraîner des erreurs silencieuses ou des problèmes de performance.
Point d’entrée de l’application
Le point d’entrée, souvent nommé app.py
ou main.py
, est le fichier qui va initialiser votre application Flask.
Il a trois responsabilités principales :
-
Créer l’instance Flask : c’est cette instance qui sera le cœur de votre application, celle qui reçoit les requêtes HTTP et qui les transmet aux routes correspondantes.
-
Charger la configuration : paramètres de base de données, clé secrète, mode debug…
-
Lancer l’application : il démarre le serveur Flask et connecte tous les modules ensemble.
Pourquoi c’est important : si ce fichier contient trop de logique métier, votre application devient rapidement difficile à comprendre et à tester. Le point d’entrée doit rester minimal, comme un chef d’orchestre qui coordonne les musiciens sans jouer de chaque instrument.
Configuration de l’application
La configuration est un concept crucial : elle centralise tous les paramètres variables de votre application.
-
Paramètres sensibles : clé secrète, mots de passe de base de données, tokens d’API
-
Paramètres environnementaux : debug, chemins de fichiers, URLs
-
Paramètres fonctionnels : taille des requêtes, limites de pagination, seuils pour des modèles ML
Bonnes pratiques :
-
Stocker ces paramètres dans un fichier
config.py
ou mieux, dans des variables d’environnement, pour éviter de les exposer dans le code source. -
Séparer les configurations selon l’environnement : développement, test, production.
Pourquoi c’est important : la configuration centralisée rend votre application plus sécurisée et plus portable, car vous pouvez changer d’environnement sans modifier le code.
Modularité avec les Blueprints
Les Blueprints sont la façon dont Flask permet de modulariser une application. Chaque Blueprint correspond à un module autonome avec ses routes et éventuellement ses modèles et vues.
Exemple concret :
-
users
: gère l’inscription, la connexion, la récupération de mot de passe -
products
: gère la création, la lecture, la mise à jour et la suppression de produits -
orders
: gère les commandes, les paiements et l’historique
Pourquoi utiliser les Blueprints :
-
Ils isolent la logique de chaque fonctionnalité
-
Ils facilitent le travail en équipe : deux développeurs peuvent travailler sur des Blueprints différents sans conflits
-
Ils permettent de réutiliser du code ou de transformer un module en package indépendant
Si tu es data scientist, tu peux même imaginer un Blueprint spécifique pour servir un modèle de machine learning, séparé des fonctionnalités classiques comme la gestion des utilisateurs.
Séparation de la logique métier
Un principe fondamental : ne jamais mettre la logique métier dans les routes.
-
La route ne fait que recevoir la requête, la valider, appeler la logique métier et retourner la réponse.
-
La logique métier, regroupée dans des services ou modules, effectue les calculs, la validation et les transformations.
Exemple concret :
Pour un modèle de scoring d’utilisateurs :
-
La route
/predict
reçoit des données JSON -
Le service
scoring_service.py
applique le modèle ML et calcule le score -
La route retourne la réponse formatée en JSON
Pourquoi c’est important :
-
Facilite les tests unitaires
-
Permet de modifier la logique sans toucher aux routes
-
Rend le code plus lisible et évolutif
Modèles de données
Lorsque votre API interagit avec une base de données, il est essentiel de définir des modèles : des classes qui représentent les entités et leurs relations.
-
Définissent les champs et leur type (string, integer, date…)
-
Définissent les relations (un utilisateur peut avoir plusieurs commandes)
-
Appliquent des contraintes et validations
Pourquoi c’est important :
-
Garantit la cohérence des données
-
Facilite l’interaction avec la base de données via un ORM comme SQLAlchemy
-
Centralise la définition des entités, ce qui simplifie la maintenance
Schémas et validation des données
Pour garantir que votre API reçoit et renvoie des données correctes, on utilise des schémas de validation avec des outils comme Marshmallow ou Pydantic.
Ils permettent de :
-
Vérifier que les données envoyées par le client respectent les types et contraintes
-
Sérialiser et désérialiser les objets Python en JSON
-
Appliquer des transformations ou des valeurs par défaut
Pourquoi c’est crucial pour les data scientists : si vous envoyez des données incorrectes à un modèle ML, vous risquez des erreurs ou des prédictions absurdes. La validation protège donc à la fois votre API et vos modèles.
Utilitaires et fonctions réutilisables
Certains traitements reviennent souvent : génération de tokens, hashage de mots de passe, calculs statistiques, logging.
-
Regrouper ces fonctions dans des modules
utils
ouhelpers
-
Les utiliser dans différents modules sans duplication de code
Pourquoi : Cela rend le code DRY (Don’t Repeat Yourself) et plus facile à maintenir. C’est un pilier de la bonne architecture logicielle.
Gestion des erreurs et réponses standardisées
Une API doit être prévisible pour ses consommateurs :
-
Chaque réponse doit suivre un format standard (
status
,message
,data
) -
Les erreurs doivent être interceptées et renvoyées de manière uniforme
-
Flask permet de définir des gestionnaires d’erreurs globaux, évitant ainsi de répéter du code
Pourquoi : cela rend votre API plus robuste et facilite l’intégration côté client, notamment pour des tableaux de bord ou des applications de data visualisation.
Tests et validation
Les tests sont essentiels pour garantir que chaque module fonctionne correctement.
-
Tests unitaires : vérifient la logique métier sans dépendre de Flask
-
Tests fonctionnels : vérifient le comportement complet des routes
-
Isolation : utilisation de bases temporaires ou mocks pour tester les modules
Pourquoi : une API mal testée peut causer des résultats incorrects, ce qui est critique si votre API sert des modèles ML en production.
Conclusion
Structurer une API Flask ne consiste pas à créer des fichiers ou dossiers de manière arbitraire. Il s’agit de penser l’architecture globale, en respectant ces principes :
-
Point d’entrée minimal
-
Configuration centralisée et sécurisée
-
Blueprints pour chaque fonctionnalité
-
Logique métier séparée des routes
-
Modèles pour gérer les données
-
Schémas pour validation et sérialisation
-
Utilitaires pour les fonctions récurrentes
-
Gestion des erreurs standardisée
-
Tests pour garantir la fiabilité
En respectant cette structure, vous créez une API maintenable, testable, scalable et sécurisée, capable de servir des applications complexes, y compris des modèles de machine learning.