Flask-Restful est une extension pour le framework Flask qui facilite la création rapide d'APIs respectant l'architecture REST. Elle encourage les bonnes pratiques en proposant une structuration par ressources et fournit des outils intégrés pour la validation des entrées et le formatage des sorties.
Installation du framework
Pour intégrer Flask-Restful à votre environnement Python, vous pouvez utiliser le gestionnaire de paquets pip :
pip install flask-restful
Si vous préférez installer la version de développement depuis les sources :
git clone https://github.com/twilio/flask-restful.git
cd flask-restful
python setup.py install
Mise en œuvre d'une ressource de base
L'unité de base dans Flask-Restful est la Resource. Chaque classe héritant de Resource peut définir des méthodes correspondant aux verbes HTTP (GET, POST, PUT, DELETE).
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class StatutServeur(Resource):
def get(self):
return {'etat': 'actif', 'version': '1.0.2'}
api.add_resource(StatutServeur, '/status')
if __name__ == '__main__':
app.run(debug=True)
Gestion des entrées avec RequestParser
Flask-Restful propose l'outil reqparse pour extraire et valider les paramètres envoyés par le client, qu'ils soient dans l'URL, le corps de la requête (JSON/Form) ou les en-têtes.
from flask_restful import reqparse, Resource
# Configuration de l'analyseur de requêtes
analyseur = reqparse.RequestParser()
analyseur.add_argument('titre', type=str, required=True, help='Le titre est obligatoire')
analyseur.add_argument('priorite', type=int, default=1, location='json')
analyseur.add_argument('tags', type=str, action='append') # Pour accepter plusieurs valeurs
class GestionTache(Resource):
def post(self):
donnees = analyseur.parse_args()
# Traitement des données validées
return {"message": "Tâche créée", "data": donnees}, 201
Options courantes de add_argument :
- dest : Définit le nom de la clé dans le dictionnaire de sortie.
- location : Définit où chercher la valeur (
args,json,form,headers,cookies). - choices : Liste de valeurs autorisées.
- trim : Suppirme les espaces avant et après la chaîne de caractères.
Formatage des données de sortie (Serialization)
Pour contrôler précisément la structure JSON renvoyée au client, on utilise le module fields combiné au décorateur marshal_with.
from flask_restful import fields, marshal_with, Resource
import datetime
# Définition de la structure de sortie
modele_utilisateur = {
'id_public': fields.Integer(attribute='id'),
'nom_complet': fields.String(attribute='username'),
'date_inscription': fields.DateTime(dt_format='iso8601'),
'est_actif': fields.Boolean(default=True),
'url_profil': fields.Url('detail_utilisateur', absolute=True)
}
class Utilisateur:
def __init__(self, id, username):
self.id = id
self.username = username
self.date_inscription = datetime.datetime.now()
class DetailUtilisateur(Resource):
@marshal_with(modele_utilisateur)
def get(self, user_id):
# Simulation d'un objet métier
user_obj = Utilisateur(id=user_id, username="JeanDupont")
return user_obj
api.add_resource(DetailUtilisateur, '/user/<int:user_id>', endpoint='detail_utilisateur')
Champs personnalisés et imbriqués
Il est fréquent de devoir renvoyer des structures complexes ou de transformer une donnée avant l'envoi.
class ChampPrix(fields.Raw):
def format(self, value):
return f"{value:.2f} EUR"
detail_produit = {
'sku': fields.String,
'nom': fields.String
}
reponse_commande = {
'commande_id': fields.Integer,
'total': ChampPrix(attribute='montant'),
'articles': fields.List(fields.Nested(detail_produit))
}
Personnalisation globale de la réponse JSON
Si vous souhaitez que toutes vos réponses API suivent un format standard (par exemple, inclure un code de statut personnalisé), vous pouvez surcharger la méthode de représentation de l'objet API.
from flask import make_response
import json
def formatage_standard(data, code, headers=None):
enveloppe = {
'status': 'success' if code < 400 else 'error',
'content': data
}
reponse = make_response(json.dumps(enveloppe), code)
reponse.headers.extend(headers or {})
return reponse
class ApiPersonnalisee(Api):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.representations = {
'application/json': formatage_standard
}
Utilisation avec les Blueprints
Pour les applications de grande envergure, il est recommandé d'utiliser les Blueprints Flask pour organiser le code par modules.
from flask import Blueprint
api_bp = Blueprint('v1', __name__)
api_v1 = Api(api_bp)
class RessourceModule(Resource):
def get(self):
return {'info': 'Réponse du module v1'}
api_v1.add_resource(RessourceModule, '/info')
# Dans le fichier principal app.py
# app.register_blueprint(api_bp, url_prefix='/api/v1')
Injection de dépendances dans les ressources
Vous pouvez passer des arguments externes (comme une instance de base de données ou de cache) à vos constructeurs de ressourcse via resource_class_kwargs.
class ServiceExterne(Resource):
def __init__(self, connecteur):
self.db = connecteur
def get(self):
return self.db.get_stats()
api.add_resource(ServiceExterne, '/stats',
resource_class_kwargs={'connecteur': mon_objet_db})