L'authentification et l'autorisation sont des aspects essentiels pour sécuriser toute application web, notamment dans les API RESTful. Dans ce contexte, FastAPI, avec son intégration native d'OAuth2, propose une solution efficace pour sécuriser l'accès aux ressources sensibles. Cette solution repose sur la gestion des jetons d'accès (tokens), permettant de garantir que seules les requêtes authentifiées et autorisées puissent accéder à des informations protégées.

Lorsque l’on parle d’OAuth2 dans FastAPI, il est crucial de comprendre comment les jetons d’accès sont générés, utilisés et validés au sein de l’application. Le processus commence souvent par la création d'un point de terminaison de connexion qui permet à l'utilisateur de s'authentifier en envoyant ses informations d'identification (généralement un nom d'utilisateur et un mot de passe). Une fois ces informations vérifiées, un jeton d'accès est généré et renvoyé à l'utilisateur. Ce jeton d'accès est ensuite utilisé pour authentifier toutes les requêtes ultérieures vers des points de terminaison sécurisés de l'API.

Un des éléments clés de cette méthode d'authentification repose sur l'utilisation de dépendances dans FastAPI. Par exemple, lorsqu'un utilisateur envoie une requête vers un point de terminaison sécurisé, FastAPI vérifie d'abord si un jeton valide est fourni. Ce jeton est ensuite analysé pour en extraire les informations d'identification de l'utilisateur, permettant ainsi de s'assurer que l'utilisateur est bien celui qu'il prétend être. Si le jeton est manquant ou invalide, une exception HTTP est levée, empêchant ainsi l'accès à la ressource demandée.

La fonction get_user_from_token est un exemple classique de l'utilisation des dépendances dans FastAPI pour extraire l'utilisateur du jeton d'accès. Elle repose sur un mécanisme simple de vérification, mais il peut facilement être étendu pour gérer des logiques plus complexes, comme la gestion des rôles ou des permissions d’accès spécifiques.

La gestion des jetons d’accès ne se limite pas seulement à leur vérification. L'utilisation des scopes dans OAuth2 permet d’ajouter une couche supplémentaire de sécurité en définissant des permissions spécifiques pour chaque jeton. Par exemple, un jeton peut être limité à des actions spécifiques comme la lecture des informations de l'utilisateur, mais pas leur modification. Cela permet de mieux contrôler l'accès aux différentes parties de l'application, offrant ainsi une sécurité fine.

Dans FastAPI, l'implémentation des scopes est relativement simple et permet de personnaliser les niveaux d'accès. Les scopes sont souvent définis sous forme de dictionnaires où chaque clé représente un scope et la valeur est une description de ce qu'il permet de faire. Lorsqu'un jeton est généré, il peut inclure un ou plusieurs scopes, et l'application peut ainsi déterminer si l'utilisateur a les droits nécessaires pour effectuer certaines actions sur une ressource.

Un autre aspect important de la sécurisation d’une API avec OAuth2 dans FastAPI est la documentation interactive générée automatiquement. FastAPI permet de visualiser l'API, y compris les points de terminaison protégés par OAuth2, grâce à une interface Swagger UI accessible via un simple navigateur. Cela permet aux développeurs et utilisateurs d’interagir avec l'API en testant les différents points de terminaison et en vérifiant que le mécanisme d'authentification fonctionne correctement. Par exemple, un utilisateur peut facilement obtenir un jeton d'accès directement à partir de l'interface Swagger UI en cliquant sur un petit icône de cadenas à côté d'un point de terminaison sécurisé.

Cette documentation interactive n’est pas seulement un outil de développement, mais aussi un moyen efficace de tester et de s’assurer que tous les points de terminaison sont correctement sécurisés. Pour aller plus loin, il est possible de personnaliser cette documentation selon les besoins du projet, par exemple, en masquant certains points de terminaison sensibles ou en ajoutant des informations spécifiques sur la gestion des jetons d'accès.

Un autre aspect essentiel à comprendre est la gestion des erreurs dans le processus d'authentification. Si un utilisateur tente d’accéder à un point de terminaison protégé sans fournir de jeton ou avec un jeton invalide, FastAPI renverra une erreur de type HTTPException, souvent avec le code 401 Unauthorized. Cela permet de garantir que les utilisateurs non authentifiés ou non autorisés ne pourront pas interagir avec les ressources protégées.

La mise en place de la sécurisation des points de terminaison avec OAuth2 doit également tenir compte de la gestion des sessions et de l’expiration des jetons. Dans un système OAuth2 classique, les jetons peuvent expirer après un certain délai, nécessitant ainsi une nouvelle authentification. Il est également courant d'implémenter un mécanisme de renouvellement de jetons, où un jeton d’actualisation (refresh token) est utilisé pour générer un nouveau jeton d’accès sans que l'utilisateur n'ait à se reconnecter.

Ainsi, en sécurisant vos API avec OAuth2 et en intégrant des fonctionnalités comme les scopes et les jetons d’actualisation, vous garantissez non seulement une protection efficace contre les accès non autorisés, mais vous améliorez aussi l’expérience de développement et d’utilisation de l'API. La gestion des jetons, la validation des scopes et la gestion des erreurs sont des aspects essentiels pour offrir une solution complète et sécurisée aux utilisateurs et développeurs de l'API.

Comment mesurer la couverture des tests et gérer les logs dans une application FastAPI ?

La couverture des tests est un indicateur clé dans le domaine du développement logiciel, permettant de mesurer l’étendue de l'exécution du code source lors du passage des tests. Cette métrique est cruciale car elle aide les développeurs à identifier les parties du code qui ne sont pas couvertes par les tests, ce qui peut potentiellement masquer des erreurs ou des comportements indésirables.

Pour utiliser cette fonctionnalité avec pytest, il est nécessaire d'installer le package pytest-cov si ce n'est pas déjà fait avec les dépendances définies dans le fichier requirements.txt. L'installation se fait avec la commande suivante : $ pip install pytest-cov. Une fois installé, il suffit de spécifier la racine du code source (dans cet exemple, le répertoire protoapp) ainsi que le répertoire des tests (tests) via l'option --cov de pytest :

bash
$ pytest --cov protoapp tests

Cette commande génère un rapport de couverture, sous forme de tableau, où chaque module est listé avec le pourcentage de couverture correspondant. Par exemple :

markdown
Name Stmts Miss Cover
------------------------------------------------- protoapp/database.py 16 0 100% protoapp/main.py 37 4 89% protoapp/schemas.py 8 8 0% ------------------------------------------------- TOTAL 61 12 80%

Un fichier binaire .coverage est également créé, contenant des informations sur la couverture des tests, et peut être utilisé avec d'autres outils pour générer des rapports plus détaillés. Par exemple, la commande suivante permet de créer un rapport au format HTML :

bash
$ coverage html

Cela génère un répertoire htmlcov contenant un fichier index.html que vous pouvez ouvrir dans un navigateur pour visualiser le rapport.

La gestion des logs dans les applications, en particulier dans un environnement comme FastAPI, revêt une importance capitale. Un système de logs bien conçu aide à détecter rapidement les erreurs, tout en fournissant des informations essentielles sur les interactions des utilisateurs, la performance du système et d'éventuelles menaces de sécurité. Il joue également un rôle important en matière de conformité et d'audit. Par conséquent, l'intégration d'un système de logging efficace est un aspect essentiel du développement d'une application robuste et évolutive.

Voici comment vous pouvez intégrer un système de logs dans une application FastAPI en utilisant le module de logging de Python. Imaginons que vous souhaitez suivre les appels API en affichant ces informations dans la console tout en les stockant dans un fichier log pour une consultation ultérieure.

Tout d'abord, définissez un logger à l'aide de la bibliothèque standard logging. Pour cela, il suffit de créer un fichier logging.py et de configurer le logger de la manière suivante :

python
import logging
client_logger = logging.getLogger("client.logger") client_logger.setLevel(logging.INFO)

Ensuite, créez un handler pour afficher les messages de log dans la console. Cela se fait en utilisant l'objet StreamHandler de la bibliothèque logging :

python
console_handler = logging.StreamHandler()

Vous pouvez également ajouter un formateur coloré pour rendre les logs plus lisibles dans la console, en utilisant ColourizedFormatter de la bibliothèque uvicorn.logging :

python
from uvicorn.logging import ColourizedFormatter
console_formatter = ColourizedFormatter( "%(levelprefix)s CLIENT CALL - %(message)s", use_colors=True ) console_handler.setFormatter(console_formatter) client_logger.addHandler(console_handler)

En parallèle, vous pouvez configurer un autre handler pour écrire les logs dans un fichier, en utilisant un TimedRotatingFileHandler. Cela permet de faire tourner les fichiers de log à intervalles réguliers, ce qui évite qu'ils ne deviennent trop volumineux. Voici un exemple de configuration :

python
from logging.handlers import TimedRotatingFileHandler
file_handler = TimedRotatingFileHandler("app.log") file_formatter = logging.Formatter( "time %(asctime)s, %(levelname)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) file_handler.setFormatter(file_formatter) client_logger.addHandler(file_handler)

Une fois le logger configuré, il faut l'intégrer dans la gestion des requêtes de FastAPI. Cela peut être réalisé via un middleware qui enregistre les informations de chaque appel dans les logs. Par exemple :

python
@app.middleware("http")
async def log_requests(request: Request, call_next):
client_logger.info(
f"method: {request.method}, call: {request.url.path}, ip: {request.client.host}" ) response = await call_next(request) return response

Cela permet de capturer les détails de chaque requête, comme la méthode HTTP, l'URL appelée et l'adresse IP du client.

Une fois que l'application tourne, vous pouvez observer les logs dans la console ainsi que dans le fichier app.log. Ces logs fourniront un aperçu précis des appels API effectués.

Un bon système de logs repose sur certaines pratiques essentielles. Il est important de bien choisir les niveaux de log (INFO, WARNING, ERROR, CRITICAL), de maintenir un format uniforme dans les messages de log, et d'inclure des informations contextuelles utiles, telles que l'identifiant de l'utilisateur ou de la transaction. Il est également crucial de ne jamais inclure d'informations sensibles, telles que les mots de passe ou les clés API, dans les logs. Enfin, il faut veiller à ce que la quantité de logs générée ne nuise pas à la performance de l'application.

Un logging bien conçu est non seulement utile pour le débogage mais aussi pour la maintenance et la sécurité de l'application. Il permet d'identifier les problèmes en temps réel et de suivre l'activité des utilisateurs de manière transparente. Pour une gestion de logs optimale, il est recommandé de consulter la documentation officielle de Python sur le logging ainsi que les bonnes pratiques partagées sur des blogs spécialisés.

Comment gérer les transactions et la concurrence dans les systèmes de bases de données ?

Dans le domaine des systèmes de bases de données, l'un des défis fondamentaux réside dans la gestion des transactions concurrentes provenant de plusieurs utilisateurs tout en préservant la cohérence et l'intégrité des données. En effet, les transactions peuvent avoir des besoins différents en termes d'accès et de modification des données, et peuvent entrer en conflit avec d'autres transactions en cours. La gestion de cette concurrence repose sur des mécanismes complexes permettant de garantir un équilibre entre performance, disponibilité et cohérence des données.

L'un des moyens classiques pour gérer cette concurrence est l'utilisation des verrous. Ces mécanismes servent à empêcher les opérations incompatibles ou non autorisées sur les données. Cependant, l'utilisation des verrous n'est pas sans compromis. Elle peut introduire des trade-offs entre la performance, la disponibilité du système et la correction des données. Par exemple, certains types de verrous peuvent être appliqués à différents niveaux de granularité, comme au niveau de la table ou de la ligne. SQLite, par exemple, permet uniquement des verrous au niveau de la base de données, tandis que PostgreSQL permet des verrous jusqu’au niveau des lignes d'une table.

Un autre aspect essentiel de la gestion des transactions concurrentes est le concept de niveaux d'isolation, qui définit le degré d'isolement qu'une transaction doit avoir par rapport aux effets d'autres transactions concurrentes. L'isolement garantit que les transactions maintiennent la cohérence des données, même lorsque plusieurs utilisateurs accèdent et modifient les données simultanément. Le standard SQL définit quatre niveaux d'isolation, chacun offrant des compromis différents entre la concurrence et la cohérence des données.

  1. READ UNCOMMITTED : Les transactions à ce niveau permettent des lectures dites « sales », c'est-à-dire qu'une transaction peut voir les modifications non validées effectuées par d'autres transactions concurrentes. Les lectures non répétables et les lectures fantômes peuvent survenir. Ce niveau d'isolement permet une très grande concurrence mais au prix d'une faible cohérence des données.

  2. READ COMMITTED : À ce niveau, les transactions ne voient que les modifications validées par d'autres transactions. Les lectures sales sont évitées, mais des lectures non répétables peuvent encore se produire, tout comme des lectures fantômes. Ce niveau représente un compromis entre concurrence et cohérence des données.

  3. REPEATABLE READ : Ce niveau garantit que les données visibles pour une transaction au début de son exécution restent constantes tout au long de son déroulement. Les modifications effectuées par d'autres transactions après le début de l'exécution de la transaction en cours ne seront pas visibles. Les lectures non répétables sont évitées, mais des lectures fantômes peuvent encore se produire. Ce niveau d'isolation assure une cohérence plus forte au prix d'une moindre concurrence.

  4. SERIALIZABLE : Les transactions à ce niveau sont exécutées de manière sérielle, c’est-à-dire une après l’autre, comme si elles se déroulaient en séquence. Ce niveau offre la plus grande cohérence des données, empêchant à la fois les lectures non répétables et les lectures fantômes, mais peut réduire considérablement la concurrence en raison des verrous plus stricts.

SQLite et MySQL, tout comme PostgreSQL, offrent différentes options pour définir les niveaux d'isolation, ce qui influe directement sur l'architecture et la conception du système de base de données. Il est donc crucial de comprendre les principes des stratégies de verrouillage et leur relation avec les comportements des transactions et la logique métier de l’application. Par exemple, dans un système où la performance est prioritaire, des niveaux d'isolation plus faibles peuvent être choisis pour permettre une plus grande concurrence, mais cela pourrait compromettre la consistance des données.

Lorsque la base de données utilisée supporte ces options, SQLAlchemy permet de définir le niveau d'isolation au moment de l'initialisation de la connexion ou de l'engin de base de données. Cela permet de spécifier les comportements souhaités, en fonction des besoins spécifiques de l'application. Par exemple, pour PostgreSQL, l'initialisation de l’engin avec un niveau d’isolation « REPEATABLE READ » peut être réalisée de la manière suivante :

python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker eng = create_engine( "postgresql+psycopg2://scott:tiger@localhost/test", isolation_level="REPEATABLE READ", ) Session = sessionmaker(eng)

L’implémentation de ces choix en termes de verrous et de niveaux d'isolation affecte non seulement la performance des systèmes de bases de données mais aussi la manière dont les applications devront gérer la concurrence, selon qu'elles privilégient la cohérence ou la rapidité des transactions.

Il est également essentiel de se rappeler que chaque base de données a ses propres comportements en matière de verrouillage et d’isolation, ce qui peut influencer directement le choix des mécanismes de gestion des transactions. Les bonnes pratiques en matière de gestion des verrous incluent une compréhension claire des besoins métier, une évaluation minutieuse des performances et des compromis entre cohérence et disponibilité.

En résumé, la gestion des transactions concurrentes et des mécanismes de verrouillage ne se limite pas simplement à des considérations techniques, mais doit aussi être en harmonie avec les exigences spécifiques du système et de l’application.

Comment démarrer avec FastAPI : les bases essentielles pour créer des API performantes

FastAPI est un framework moderne, hautement performant, utilisé pour la création d'API et d'applications web en Python. L'attrait de FastAPI réside dans sa rapidité d'exécution, sa simplicité d’utilisation et la richesse de sa documentation, des atouts qui en font un choix privilégié pour les développeurs cherchant à construire des applications web évolutives et efficaces. Cette première étape vers l’utilisation de FastAPI vous permettra de vous familiariser avec son environnement de développement, de créer votre premier projet et d’en explorer les concepts fondamentaux.

L’un des principaux avantages de FastAPI est sa capacité à offrir des performances exceptionnelles tout en maintenant une facilité d’utilisation inédite. Ce cadre de travail est conçu pour optimiser le développement d’APIs RESTful en exploitant au maximum la puissance de Python 3.9 ou supérieur. Pour démarrer, il est essentiel que vous possédiez une compréhension de base de Python, de son syntaxe et de ses concepts. Une connaissance préalable du développement web, en particulier des principes liés au protocole HTTP, aux APIs RESTful et au format JSON, vous sera également bénéfique.

La première étape consiste à préparer l'environnement de développement. Vous devez vous assurer que votre système dispose de Python 3.9 ou supérieur. Les systèmes d’exploitation compatibles sont Windows, macOS et Linux, chacun d’entre eux offrant des avantages et des inconvénients en fonction des préférences personnelles et de l’infrastructure de développement. Si vous travaillez sur Windows, il est conseillé d’adapter les commandes Unix-like à votre terminal, en prenant soin de manipuler les caractères de saut de ligne de manière appropriée.

Une fois l'environnement en place, il est temps de passer à la création d'un projet FastAPI. L'initialisation d'un projet est simple et ne nécessite que quelques étapes essentielles. Après l’installation de FastAPI et de son serveur ASGI, Uvicorn, vous serez prêt à créer vos premiers fichiers de projet et à définir les éléments de base d’une application web. Dans ce chapitre, l’objectif est de comprendre l’architecture du framework et de définir des points de terminaison API (endpoints) de manière intuitive.

FastAPI repose sur des principes fondamentaux comme la gestion des méthodes HTTP (GET, POST, PUT, DELETE) et la manipulation des données via des paramètres de requête et des corps de requêtes JSON. En définissant votre premier endpoint, vous apprendrez à accepter des paramètres d’URL, à effectuer des validations de données et à répondre correctement aux requêtes des utilisateurs. La gestion des paramètres de chemin et de requête est cruciale pour construire des interfaces claires et performantes. Par exemple, vous pourrez créer un endpoint qui prend un identifiant en paramètre et renvoie les informations associées à cet identifiant, ou encore définir des paramètres de requête pour filtrer les résultats renvoyés par votre API.

FastAPI offre également un système de validation automatique des données grâce à Pydantic, un module intégré. Lorsqu'un utilisateur soumet des données via un formulaire ou une API, FastAPI valide automatiquement la conformité des données par rapport aux modèles définis avec Pydantic. Cela réduit considérablement la nécessité d'écrire des fonctions de validation manuelles et garantit que les données envoyées par les utilisateurs respectent un format cohérent. De plus, cette validation est effectuée de manière très performante, ce qui fait partie des raisons pour lesquelles FastAPI est apprécié pour sa rapidité.

Outre les bases de l’API, FastAPI vous permet d’ajouter des fonctionnalités supplémentaires telles que la documentation interactive de vos API via Swagger UI et ReDoc. Cette documentation, générée automatiquement à partir de votre code, facilite grandement le test et l’exploration des API, et améliore l’expérience utilisateur des développeurs utilisant vos services.

Un autre aspect clé de FastAPI est la gestion des erreurs. Lors de la création d'applications complexes, la gestion des erreurs est essentielle pour assurer une communication claire avec les utilisateurs. FastAPI permet de personnaliser les réponses d’erreur afin de fournir des informations pertinentes en cas d’échec des requêtes, ce qui est crucial pour le débogage et l’amélioration de l’expérience utilisateur.

En complément de ces éléments, il est recommandé de suivre des bonnes pratiques telles que l’utilisation de Git pour le contrôle de version et la gestion des projets. Ce processus garantit que vous pouvez suivre les évolutions de votre code et collaborer efficacement avec d’autres développeurs. Il est également important de familiariser avec les bases de données, qu’elles soient SQL ou NoSQL, car les applications FastAPI interagiront souvent avec des systèmes de gestion de données.

Le développement d’applications avec FastAPI est d’une grande simplicité, mais il est important de ne pas se précipiter. Chaque étape, depuis la configuration de l’environnement jusqu’à la définition des premiers endpoints, vous fournit les bases solides nécessaires pour construire des systèmes complexes par la suite. L’apprentissage se fait progressivement, et une bonne maîtrise de ces principes fondamentaux ouvre la voie à des applications robustes et scalables.

Il convient de rappeler que l'un des atouts majeurs de FastAPI est sa documentation complète et détaillée, un véritable guide à chaque étape du développement. Il est donc conseillé de s'y référer fréquemment pour approfondir sa compréhension et éviter les erreurs courantes. Enfin, pour aller au-delà des premiers pas, il est crucial de s’initier à des concepts avancés comme la gestion de la sécurité, l'optimisation des performances ou encore l'intégration avec des services externes, tels que les systèmes de files d'attente ou les services cloud.

Comment implémenter l'internationalisation et la localisation dans une API avec FastAPI ?

L'internationalisation (i18n) et la localisation (l10n) sont des concepts essentiels pour rendre les applications accessibles à un public mondial. Dans le cadre du développement d'API, ces pratiques permettent d'adapter le contenu en fonction des préférences linguistiques et des paramètres régionaux des utilisateurs. Dans cet article, nous allons explorer comment intégrer ces concepts dans une API utilisant FastAPI, à l'aide de la bibliothèque Babel et de quelques pratiques recommandées.

Le point de départ consiste à définir la fonction resolve_accept_language, qui permet de déterminer la langue préférée de l'utilisateur à partir de l'en-tête HTTP Accept-Language. Cette fonction traite le paramètre Accept-Language pour extraire les différentes préférences de langue et leur poids associé (indiqué par le paramètre q). Le code suivant permet de mettre en œuvre cette logique :

python
from babel import Locale, negotiate_locale
def resolve_accept_language(accept_language: str = Header("en-US")) -> Locale:
client_locales = []
for language_q in accept_language.split(","): if ";q=" in language_q: language, q = language_q.split(";q=") else: language, q = (language_q, float("inf")) try: Locale.parse(language, sep="-") client_locales.append((language, float(q))) except ValueError: continue client_locales.sort(key=lambda x: x[1], reverse=True) locales = [locale for locale, _ in client_locales] locale = negotiate_locale([str(locale) for locale in locales], SUPPORTED_LOCALES) if locale is None: locale = "en_US" return locale

Cette fonction commence par analyser l'en-tête Accept-Language, qui contient une liste de langues et de poids associés. Ensuite, elle trie les langues par préférence et utilise la fonction negotiate_locale de Babel pour trouver la langue la plus appropriée parmi les locales supportées.

Une fois cette fonction en place, vous pouvez l'utiliser pour localiser les réponses de votre API. Par exemple, vous pouvez définir un endpoint qui retourne un message de bienvenue en fonction de la langue préférée de l'utilisateur. Voici comment procéder pour créer un endpoint /homepage dans un fichier internationalization.py :

python
from fastapi import APIRouter router = APIRouter(tags=["Localizad Content Endpoints"]) home_page_content = { "en_US": "Welcome to Trip Platform", "fr_FR": "Bienvenue sur Trip Platform", } @router.get("/homepage")
async def home(request: Request, language: Annotated[resolve_accept_language, Depends()]):
return {"message": home_page_content[language]}

Dans cet exemple, un dictionnaire mappe chaque langue à une chaîne de texte. En fonction de la langue renvoyée par la fonction resolve_accept_language, le message correspondant est retourné.

Pour rendre l'application plus réaliste, il est conseillé de stocker ces contenus dans une base de données, permettant ainsi de gérer dynamiquement les traductions. Vous pouvez appliquer une logique similaire pour gérer d'autres aspects de la localisation, comme les devises. Par exemple, pour un endpoint /show/currency, la fonction suivante peut être utilisée pour déterminer la devise en fonction de la langue :

python
async def get_currency(language: Annotated[resolve_accept_language, Depends()]): currencies = { "en_US": "USD", "fr_FR": "EUR", } return currencies[language]

Ensuite, un endpoint /show/currency peut être défini pour renvoyer la devise et son nom complet :

python
from babel.numbers import get_currency_name
@router.get("/show/currency") async def show_currency(currency: Annotated[get_currency, Depends()], language: Annotated[resolve_accept_language, Depends()]): currency_name = get_currency_name(currency, locale=language) return {"currency": currency, "currency_name": currency_name}

Avec cette approche, l'API peut répondre de manière localisée en fonction des préférences de langue et de région de l'utilisateur, rendant l'application plus accessible et conviviale à l'international.

Dans un contexte de performance, il est également crucial d'optimiser les applications pour garantir leur scalabilité, notamment lorsqu'elles traitent des charges importantes. Pour ce faire, l'utilisation de profils de performance peut permettre de détecter les goulots d'étranglement et d'améliorer l'efficacité. Le package pyinstrument est un excellent outil pour profiler les applications FastAPI.

L'intégration de cette fonctionnalité dans votre application peut être réalisée en ajoutant un middleware personnalisé qui démarre et arrête le profiler pour chaque requête traitée. Cela permet de capturer des informations détaillées sur le temps d'exécution de chaque endpoint et de générer un rapport au format HTML, qui pourra être consulté pour analyser les performances du serveur.

Une fois que l'internationalisation et la localisation sont mises en place, il est important de vérifier régulièrement que toutes les traductions sont correctement rendues et que les formats régionaux (monétaires, numériques, etc.) sont adaptés aux conventions locales. Les erreurs fréquentes incluent l'oubli de traduire certains contenus ou une mauvaise gestion des formats numériques ou des unités de mesure.