$ python3 --version
Dans le cadre d’un projet, j’ai eu besoin de développer une API rapidement. Je me suis alors posée la question de l’outil à utiliser. En faisant quelques recherches, je suis tombée plusieurs fois sur Flask. Ayant déjà fait un peu de python, je me suis lancée dans la découverte de ce framework…
La première version de Flask date de 2010. Il s’agit d’un framework de développement web en python. Ce framework open-source est qualifié de micro-framework car il est très léger. Il est particulièrement adapté dans le cas de petites applications ou de PoC (Proof of Concept), ce qui correspond tout à fait à notre cas d’usage.
Flask est utilisé par de nombreux développeurs. On peut retrouver son utilisation dans des sites tels que LinkedIn ou encore Pinterest.
Flask permet une prise en main simple et rapide, tout en permettant d’évoluer vers des applications plus complexes. En 5 lignes seulement, il est possible de créer une application web simplifiée.
Commencez par vérifier que python est bien installé sur votre ordinateur.
$ python3 --version
Si ce n’est pas le cas, installez-le :
$ sudo apt install python3
Pour installer python sur d’autres OS que Linux : https://www.python.org/downloads/
Créons un dossier dans lequel mettre notre nouveau projet. Appelons le bookshop-api
:
$ mkdir bookshop-api
Afin de versionner notre api, nous allons initialiser un nouveau dépôt git :
$ cd bookshop-api
$ git init
N’oublions pas de créer un fichier .gitignore
qui comportera les fichiers/dossiers qu’on ne veut pas versionner ni partager.
Nous le remplirons par la suite.
$ touch .gitignore
Il est recommandé de créer un environnement virtuel pour chaque projet sur lequel on travaille, dans lequel on installera localement les packages dont nous avons besoin. En effet, cela permet de travailler sur différents projets sans se soucier de la compatibilité entre les versions des librairies des différents projets.
Pour créer un nouvel environnement virtuel, lancer à la racine du projet :
$ cd bookshop-api
$ python3 -m venv <name_of_virtual_env>
Appelons venv
notre environnement virtuel.
Maintenant que nous l’avons créé, il faut l’activer :
$ source venv/bin/activate
L’environnement virtuel ne doit pas être versionné/partagé.
Pour cela nous ajoutons la ligne suivante dans le fichier .gitigore
:
/venv/
Entrons maintenant dans le vif du sujet : l’installation de Flask.
Pour installer Flask dans l’environnement virtuel :
$ pip install flask
$ python -c "import flask; print(flask.__version__)"
$ pip install -U flask-cors
$ pip install python-dotenv
L’installation du package flask-cors
permet la gestion du CORS. Pour en savoir plus sur ce package, rendez-vous ici.
Pour en savoir plus sur le CORS, ou "Cross-origin resource sharing", rendez-vous ici.
Nous verrons plus bas l’utilisation du package python-dotenv
.
Créer un fichier main.py
à la racine du projet, qui sera le point de départ de notre API.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello World!'
Comme vous pouvez le constater, il ne suffit vraiment que de 5 lignes pour créer un premier endpoint.
Définissons le nom de l’application ainsi que l’environnement de développement.
La variable FLASK_APP
permet d’indiquer à Flask où trouver l’application.
Ici, le nom de l’application est main
car le fichier à lancer est main.py
.
La variable FLASK_ENV
indique quant à elle à Flask dans quel mode exécuter l’application.
Ici, nous voulons l’exécuter en mode developpement, afin d’activer automatiquement le mode de debug.
La valeur par défaut étant FLASK_ENV=production
.
Nous allons enregistrer ces variables d’environnement dans un fichier .env
situé à la racine du projet :
FLASK_APP=main
FLASK_ENV=development
N’oubliez pas d’ajouter ce fichier .env
dans votre .gitignore.
Les variables d’environnement ne sont pas supposées être partagées, surtout dans le cas où il s’agit de variables secrètes.
Le package python-dotenv
est nécessaire pour que ce fichier contenant les variables d’environnement soit automatiquement lu au lancement de l’application.
C’est pourquoi nous l’avons installé lors de la mise en place de l’application.
Pour démarrer le serveur Flask, lancer la commande suivante :
$ flask run
La console affiche alors les lignes suivantes :
* Serving Flask app "main" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 813-894-335
En se rendant à l’adresse http://127.0.0.1:5000/
, la phrase "Hello World" apparaît sur la page du navigateur.
Ce n’est pas tout d’afficher un "Hello World", passons maintenant aux choses sérieuses : la création des routes de notre librairie en ligne.
Dans le cadre de ce projet, j’avais besoin de répondre aux besoins suivants :
Récupérer la liste de tous les livres ;
Récupérer un livre par son id ;
Créer un livre ;
Modifier un livre ;
Supprimer un livre.
Nous allons donc créer 5 endpoints correspondant aux 5 opérations CREATE, READ, UPDATE, DELETE, et SEARCH dans le fichier main.py
:
from flask import Flask, request, jsonify
from flask_cors import CORS
from utils.seeds import default_books
from domain.Book import Book, from_json
app = Flask(__name__)
CORS(app, supports_credentials=True)
@app.route('/')
def hello():
return 'Hello World!'
@app.route('/books', methods=['GET'])
def get_all_books():
return jsonify([book.to_json() for book in default_books]), 200
@app.route('/books/<book_id>', methods=['GET'])
def get_one_book(book_id):
for book in default_books:
if str(book.id) == str(book_id):
return book.to_json(), 200
return jsonify({'error': 'book not found'}), 404
@app.route('/books', methods=['POST'])
def create_book():
data = request.get_json()
book = from_json(data)
book.id = len(default_books) + 1
default_books.append(book)
return jsonify({'message': 'book successfully created'}), 200
@app.route('/books/<book_id>', methods=['PUT'])
def update_book(book_id):
data = request.get_json()
updated_book = from_json(data)
for book in default_books:
if str(book.id) == str(book_id):
index = default_books.index(book)
default_books[index] = updated_book
return jsonify({'message': "book successfully updated"}), 200
return jsonify({'error': 'book not found'}), 404
@app.route('/books/<book_id>', methods=['DELETE'])
def delete_book(book_id):
for book in default_books:
if str(book.id) == str(book_id):
default_books.remove(book)
return jsonify({'message': 'book successfully deleted'}), 200
return jsonify({'error': 'book not found'}), 404
La classe Book se trouve dans le fichier Book.py
:
import string
class Book:
def __init__(self, title: string, code_name: string, author: string, quantity: int, publish_date: string,
id: int = 0) -> None:
self.id = id
self.title = title
self.code_name = code_name
self.author = author
self.quantity = quantity
self.publish_date = publish_date
def to_json(self):
return {
'id': self.id,
'title': self.title,
'codeName': self.code_name,
'author': self.author,
'publishDate': self.publish_date,
'quantity': self.quantity
}
def from_json(data):
return Book(
data['title'], data['codeName'], data['author'], data['quantity'], data['publishDate'], data['id']
)
La liste de livres default_books se trouve dans le fichier seeds.py
from domain.Book import Book
b1 = Book("Juste un regard", "juste_un_regard", "Harlan Coben", 8, 2010, 1)
b2 = Book("Ne le dis à personne", "ne_le_dis_a_personne", "Harlan Coben", 1, 2005, 2)
b3 = Book("Dans les bois", "dans_les_bois", "Harlan Coben", 5, 2020, 3)
b4 = Book("Balle de match", "balle_de_match", "Harlan Coben", 3, 2007, 4)
b5 = Book("Disparu à jamais", "disparu_a_jamais", "Harlan Coben", 3, 2003, 5)
b6 = Book("Promets moi", "promets_moi", "Harlan Coben", 7, 1999, 6)
default_books: [Book] = [b1, b2, b3, b4, b5, b6]
Requête curl :
curl http://127.0.0.1:5000/books
Résultat :
[
{
"author": "Harlan Coben",
"codeName": "innocent",
"id": 1,
"publishDate": 2005,
"quantity": 10,
"title": "Innocent"
},
{
"author": "Harlan Coben",
"codeName": "ne_le_dis_a_personne",
"id": 2,
"publishDate": 2001,
"quantity": 7,
"title": "Ne le dis à personne"
},
{
"author": "Harlan Coben",
"codeName": "dans_les_bois",
"id": 3,
"publishDate": 2007,
"quantity": 12,
"title": "Dans les bois"
},
{
"author": "Harlan Coben",
"codeName": "balle_de_match",
"id": 4,
"publishDate": 2006,
"quantity": 3,
"title": "Balle de match"
}
]
Requête curl :
curl http://127.0.0.1:5000/books/1
Résultat :
{
"author": "Harlan Coben",
"codeName": "innocent",
"id": 1,
"publishDate": 2005,
"quantity": 10,
"title": "Innocent"
}
Requête curl :
curl -X POST http://127.0.0.1:5000/books
-H "Content-Type: application/json"
-d '{"author": "Harlan Coben", "title": "Juste un regard", "publishDate": 2004, \
"quantity": 12, "codeName": "juste_un_regard", "id": ""}'
Résultat :
{
"message": "book successfully created"
}
Requête curl :
curl -X PUT http://127.0.0.1:5000/books/5
-H "Content-Type: application/json"
-d '{"author": "Harlan Coben", "title": "Juste un regard", "publishDate": 2004, "quantity": 20, \
"codeName": "juste_un_regard", "id": 5}'
Résultat :
{
"message": "book successfully updated"
}
Requête curl :
curl -X DELETE http://127.0.0.1:5000/books/46
Résultat :
{
"message": "book successfully deleted"
}
Requête curl :
curl http://127.0.0.1:5000/books/157
Résultat :
{
"error": "book not found"
}
Le choix de Flask était adapté pour mon cas d’usage. En effet, la prise en main a été très facile, et une API simplifiée a pu être créée en quelques lignes.
Python est un langage très utilisé, et cela vaut le coup de s’y mettre pour utiliser Flask. En effet, la montée en compétence est très rapide.
Flask étant un micro-framework, il faut tout développer soi-même tandis qu’avec un framework plus complet tel que Django, le développement de certaines fonctionnalité peut être facilité. De plus, la communauté de Flask n’est pas aussi grande que celle de Django.
Cependant, il faut garder à l’esprit que l’utilisation de Flask est surtout recommandée pour de petites applications, pour lesquelles Flask est le choix idéal.
Pour aller plus loin :
Flask permet de renvoyer des templates HTML directement. Ayant déjà un front et n’ayant que besoin d’une API, ce sujet n’a pas été abordé ici mais vous pourrez trouver de la documentation à ce sujet sur le site DigitalOcean.
La connexion avec une base de données n’a pas été traitée dans cet article, mais elle peut également se faire aisément avec Flask.