API REST avec Flask : Tutoriel Intermédiaire
Pourquoi API REST avec Flask ?
L'API REST (Representational State Transfer) est un style d'architecture pour les applications web qui utilise des méthodes HTTP pour interagir entre le client et le serveur. Flask, une plateforme web populaire en Python, offre une facilité de mise en œuvre rapide et efficace des API REST.
Un cas concret : Vous travaillez sur un projet de gestion de tâches. Pour permettre à d'autres applications de vous intégrer (par exemple, une application mobile), vous voulez créer une API REST qui expose les fonctionnalités de votre application.
Prerequis
- Connaissance des bases de Python
- Compréhension des concepts HTTP (GET, POST, PUT, DELETE)
- Installation d'un environnement Python (Python 3.6+ recommandé)
Outils à installer :
pip install Flask
Concepts fondamentaux
1. Ressources et URI
Une ressource est une entité que vous souhaitez partager via l'API, comme une tâche ou un utilisateur. Une URI (Uniform Resource Identifier) est l'adresse de cette ressource.
## Représentation d'une URI pour une tâche
/tasks/<int:task_id>
2. Méthodes HTTP
Chaque méthode HTTP correspond à une action sur la ressource :
- GET : Récupérer les données de la ressource
- POST : Créer une nouvelle ressource
- PUT : Mettre à jour une ressource existante
- DELETE : Supprimer une ressource
3. Objets JSON
Les API REST utilisent principalement le format JSON (JavaScript Object Notation) pour échanger les données.
## Exemple de réponse JSON
{
"id": 1,
"title": "Faire les courses",
"completed": False
}
4. Middleware
Le middleware est utilisé pour ajouter des fonctionnalités avant ou après l'exécution d'une requête.
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.before_request
def before_request():
print("Request received")
@app.after_request
def after_request(response):
print("Response sent")
return response
5. Sérialisation et désérialisation
La sérialisation est le processus de conversion d'un objet Python en une représentation JSON, tandis que la désérialisation est l'inverse.
from flask import Flask, request, jsonify
import json
app = Flask(__name__)
class Task:
def __init__(self, id, title, completed):
self.id = id
self.title = title
self.completed = completed
def task_to_dict(task):
return {
"id": task.id,
"title": task.title,
"completed": task.completed
}
@app.route('/tasks', methods=['GET'])
def get_tasks():
tasks = [Task(1, "Faire les courses", False), Task(2, "Lire un livre", True)]
return jsonify([task_to_dict(task) for task in tasks])
Mise en pratique : projet fil rouge
Étape 1 : Initialiser le projet
Créez un nouveau dossier pour votre projet et initialisez-le avec pipenv :
mkdir flask_api_tutorial
cd flask_api_tutorial
pipenv install Flask
pipenv shell
Étape 2 : Créer les fichiers de base
Créez les fichiers suivants :
app.pymodels.pyroutes.py
Étape 3 : Importations et structure des fichiers
## app.py
from flask import Flask, request, jsonify
from models import db, Task
from routes import task_bp
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///tasks.db'
db.init_app(app)
app.register_blueprint(task_bp)
if __name__ == '__main__':
app.run(debug=True)
python
## models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
completed = db.Column(db.Boolean, default=False)
def __repr__(self):
return f'<Task {self.title}>'
python
## routes.py
from flask import Blueprint, request, jsonify
from models import Task
task_bp = Blueprint('tasks', __name__, url_prefix='/tasks')
@task_bp.route('/', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
return jsonify([{'id': task.id, 'title': task.title, 'completed': task.completed} for task in tasks])
@task_bp.route('/', methods=['POST'])
def create_task():
data = request.get_json()
new_task = Task(title=data['title'], completed=False)
db.session.add(new_task)
db.session.commit()
return jsonify({'id': new_task.id, 'title': new_task.title, 'completed': new_task.completed}), 201
Étape 4 : Créer la base de données
flask shell
db.create_all()
exit()
Étape 5 : Exécuter l'application
python app.py
Erreurs frequentes et debugging
1. Erreur : No module named 'flask_sqlalchemy'
Code incorrect :
from flask_sqlalchemy import SQLAlchemy
Code correct :
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
2. Erreur : AttributeError: module 'flask_sqlalchemy' has no attribute 'SQLAlchemy'
Code incorrect :
db = SQLAlchemy()
Code correct :
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///tasks.db'
db = SQLAlchemy(app)
3. Erreur : AttributeError: 'Blueprint' object has no attribute 'add_url_rule'
Code incorrect :
@task_bp.route('/', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
return jsonify([{'id': task.id, 'title': task.title, 'completed': task.completed} for task in tasks])
Code correct :
from flask import Blueprint, request, jsonify
from models import db, Task
task_bp = Blueprint('tasks', __name__, url_prefix='/tasks')
@task_bp.route('/', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
return jsonify([{'id': task.id, 'title': task.title, 'completed': task.completed} for task in tasks])
Pour aller plus loin
1. Authentification et sécurité
Ajouter une couche d'authentification à votre API pour sécuriser les données.
2. Documentation automatique
Utilisez Swagger pour générer de la documentation automatique de l'API.
3. Tests unitaires
Écrire des tests unitaires pour chaque fonctionnalité de votre API.
Défi pratique :
Créez une API REST complète pour un gestionnaire de contacts. Les fonctionnalités devraient inclure la création, la lecture, la mise à jour et la suppression de contacts.