{{tag>dev python flask routes}}
====== Flask : routage ======
===== A propos des routes =====
Définir une URL ayant un sens pour l'utilisateur est préférable en général. Les deux URL ci-dessous peuvent produire le même résultat :
- https://www.example.com/script?action=33257
- https://www.example.com/create/user
Dans le second cas, on peut directement comprendre le sens de l'action à la lecture de l'URL.
Une route est une **association** entre **une URL** et **une fonction Python** dans votre application Flask. Lorsque Flask reçoit une requête HTTP, il analyse l'URL et essaie de faire correspondre cette URL à une route définie dans votre code. Si une correspondance est trouvée, Flask exécute la fonction associée et envoie la réponse au navigateur de l'utilisateur.
Le Framework Flask propose le décorateur ''route()'' pour lier une fonction à une URL. Ce décorateur s'utilise sur les objets de type ''Flask'' ou ''Bluenprint''.
===== Route statique =====
Dans sa forme la plus simple, la route associe une fonction à une URL statique :
@app.route('/hello')
def hello():
return 'Hello, World'
Dans l'exemple ci-dessus, le décorateur à la première ligne lie l'URL statique ''/hello'' à la fonction ''hello()''. Cette fonction sera exécutée lorsque l'utilisateur visitera l'URL du site web (par exemple, http://localhost:5000/hello). Il obtiendra alors le message "Hello, World".
===== Gestion des méthodes HTTP =====
Sans argument supplémentaire, une route par défaut dans Flask ne répond qu' aux requêtes **HTTP** de type **GET**. Pour qu'une route puisse prendre en compte d'autres types de méthodes HTTP (ou [[https://developer.mozilla.org/fr/docs/Web/HTTP/Reference/Methods|verbes HTTP]]) comme **POST**, **PUT** ou **DELETE** il faudra définir l'argument ''methods'' :
@app.route('/contact', methods=['GET', 'PUT'])
def contact():
if request.method == 'POST':
parse_contact_form()
else # request.method == 'GET
show_the_contact_form()
L'exemple ci-dessus traite toutes les méthodes dans une même fonction. Pour une meilleure lisibilité, il est possible de répartir le traitement des méthodes HTTP dans plusieurs fonctions.
L'exemple ci-dessous est équivalent :
@app.get('/contact')
def contact_show():
return show_the_contact_form()
@app.post('/contact')
def contact_parse():
return parse_the_contact_form()
===== Routes dynamiques =====
L'URL peut contenir des parties variables. Dasn ce cas, lors de la définition de la route, on utilise un formalisme spécifique pour identifier ces variables et les transmettre correctement à la fonction Python qui se chargera des traitements.
from markupsafe import escape
@app.route('/user/')
def show_user_profile(username):
# show the user profile for that user
return f'User {escape(username)}'
Pour déclarer une variable dans l'URL, on utilise la syntaxe ''''. On peut également utiliser un convertisseur pour définir explicitement un type avec la syntaxe ''''
Les convertisseurs disponibles sont les suivants :
^ ''string'' | (par défaut) tout texte sans "/" |
^ ''int'' | entiers positifs |
^ ''float'' | réels positifs |
^ ''path'' | textes avec "/" |
^ ''uuid'' | chaîne d'identification |
On peut réécrire l'exemple précédent en spécifiant le convertisseur ''string'' :
from markupsafe import escape
@app.route('/user/')
def show_user_profile(username):
# show the user profile for that user
return f'User {escape(username)}'
===== Gérer les erreurs 404 =====
En développement web, il est courant que les utilisateurs accèdent à des pages inexistantes : ce qui produit une erreur 404. Flask vous permet de gérer cela facilement en définissant une route spéciale pour cette erreur :
from flask import render_template
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
Ici, la fonction page_not_found() sera appelée chaque fois qu'une route non définie est accédée, et Flask renverra une réponse avec un message personnalisé et le code d'erreur HTTP 404.
Un accès répété à des ressources non existantes peut être un signe d'action malveillante. ToDo : journaliser les accès répétés à des ressources non disponibles pur permettre des réponses d'autoprotection par exemple via fail2ban.
===== Lister les routes =====
Pour afficher les routes existantes d'une application Flask depuis la CLI :
# Affiche les routes
flask routes
# En précisant l'application si nécessaire
flask --app myapp routes
Pour afficher les route depuis le shell flask :
# Lancer le shell interactif Flask
flask shell
app.url_map
===== Définir le FQDN =====
La variable **SERVER_NAME** permet de définir le nom (FQDN) du serveur.
Lorsque la variable est définie, le serveur de développement doit être lancé avec l'argument **%%--host%%**
# FQDN + port
SERVER_NAME='fairymaps.localhost:5000'
# La clé peut être générée via le module secrets
# import secrets
# print(secrets.token_hex())
SECRET_KEY = 'my-secret-token'
DB_NAME = "database.sqlite"
Pour lancer le serveur de test en spécifiant un nom FQDN :
flask --app fairymaps run --debug --host=fairymaps.localhost
===== Références =====
* [[https://flask.palletsprojects.com/en/stable/quickstart/#routing|Documentation Flask : introduction au routage (palletsprojects.com) (en)]]
* [[https://flask.palletsprojects.com/en/stable/api/#url-route-registrations|Documentation Flask : enregistrer les routes (palletsprojects.com) (en)]]
* https://flask.palletsprojects.com/en/stable/patterns/lazyloading/#converting-to-centralized-url-map
* [[https://stackoverflow.com/questions/12162634/where-do-i-define-the-domain-to-be-used-by-url-for-in-flask|Comment définir le nom de domaine de l'application Flask (stackoverflow.com)(en)]]
* [[https://stackoverflow.com/questions/13317536/get-list-of-all-routes-defined-in-the-flask-app|Comment obtenir la liste des routes dans l'application Flask (stackoverflow.com) (en)]]
* [[https://v2.ttrinfo.be/articles/internet/web-python/flask-routes-intro/|Introduction aux routes dans Flask (ttrinfo.be)]]