Prérequis
- uv et Python 3.11 ou version ultérieure. Ce guide a été testé avec Python 3.13, FastAPI 0.142, SQLAlchemy 2.1, asyncpg 0.31, Alembic 1.20 et Uvicorn 0.54.
- Un compte ClickHouse Cloud
psql, pour créer la base de données. Vous pouvez également exécuter le statementCREATE DATABASEdans la console SQL.
Créer un service ClickHouse Managed Postgres
Dans la console ClickHouse Cloud, cliquez sur New service et sélectionnez Postgres. L’instance est prête en quelques minutes. Pour une présentation pas à pas, consultez le guide de démarrage rapide.Obtenir vos informations de connexion
Cliquez sur Connect dans la barre latérale gauche de votre service. La fenêtre modale affiche votre nom d’utilisateur, votre mot de passe, le serveur et le port, et propose un sélecteur Directly / via PgBouncer. Ce guide utilise les deux types de connexion :- PgBouncer (port
6432) pour l’application. SQLAlchemy maintient un pool de connexions dans chaque worker Uvicorn, et le PgBouncer intégré permet à de nombreux workers et répliques de se partager un nombre restreint de connexions Postgres. Il fonctionne en mode pool de connexions par transaction. - Direct (port
5432) pour Alembic. Les migrations exécutent du DDL, peuvent s’exécuter longtemps et dépendre de l’état de session ; elles doivent donc communiquer directement avec Postgres.
sslmode=verify-full&sslrootcert=.... asyncpg ne lit pas ces paramètres ; copiez donc uniquement le mot de passe et l’hôte depuis la fenêtre modale. L’application transmet en effet le certificat de CA directement dans le code (voir Configurer la connexion).
Configurer le projet
Créez un projet et installez FastAPI, Uvicorn, SQLAlchemy avec son extraasyncio, asyncpg et Alembic :
Configurer la connexion
Déplacez le certificat de CA que vous avez téléchargé dans le répertoire du projet et renommez-le enca-certificate.pem.
Créez une base de données pour l’application. Remplacez <PASSWORD> et l’hôte par les valeurs affichées dans la fenêtre modale Connect :
.env à la racine du projet, ou ajoutez ces variables à votre fichier existant. Les deux URL ne diffèrent que par le port, utilisent le schéma postgresql+asyncpg et ne contiennent aucun paramètre SSL :
.env
DATABASE_CA_CERT est résolu par rapport au répertoire depuis lequel vous exécutez les commandes. Si votre mot de passe contient des caractères spéciaux tels que @, / ou #, encodez-les au format URL. Ne versionnez pas le fichier .env : il doit rester hors du contrôle de version.
Créez app/db.py. Ce fichier définit les paramètres TLS, le moteur et une fabrique de sessions partagée par le reste de l’application :
app/db.py
ssl.SSLContext créé avec PROTOCOL_TLS_CLIENT exige un certificat valide et vérifie le nom d’hôte, ce qui équivaut à sslmode=verify-full. SQLAlchemy le transmet à asyncpg via connect_args.
Si vous préférez conserver les paramètres TLS dans l’URL, ou si votre application utilise des sessions SQLAlchemy synchrones, utilisez le driver psycopg plutôt qu’asyncpg. Reposant sur libpq, il accepte les paramètres de la fenêtre modale Connect, par exemple
postgresql+psycopg://...:5432/guide_fastapi?sslmode=verify-full&sslrootcert=ca-certificate.pem, aussi bien avec create_engine qu’avec create_async_engine.Définir le modèle
Créezapp/models.py contenant un modèle SQLAlchemy typé :
app/models.py
Exécuter les migrations
Créez un environnement Alembic à partir du modèle async :migrations/env.py généré. La nouvelle version charge vos modèles pour l’autogénération et se connecte directement à Postgres avec les mêmes paramètres TLS que l’application :
migrations/env.py
sqlalchemy.url définie dans alembic.ini, car env.py crée lui-même le moteur.
Générez une migration à partir du modèle, puis appliquez-la :
migrations/versions, puis commitez-le avec votre code. Alembic enregistre la révision appliquée dans la table alembic_version. À chaque modification d’un modèle, exécutez de nouveau revision --autogenerate et upgrade head.
Ajouter les endpoints de l’API
Créezapp/main.py. Chaque requête dispose de sa propre AsyncSession grâce à une dépendance FastAPI, et le pool du moteur est fermé à l’arrêt de l’application :
app/main.py
session.commit. À la fermeture de la session, toute modification non validée est annulée. Lors d’un INSERT, SQLAlchemy récupère les valeurs générées de id et created_at à l’aide de RETURNING, si bien que create_todo n’a pas besoin d’une requête supplémentaire.
Exécuter et vérifier
Démarrez l’application :DELETE renvoie 204 No Content. Une requête portant sur un todo inexistant renvoie 404 :
pg_stat_ssl avec les mêmes paramètres TLS que l’application :
guide_fastapi puis public, et cliquez sur la table todos. La table alembic_version juste à côté contient l’historique des migrations. La table todos contient la ligne restante :
Arrêtez l’application avec Ctrl+C.
Utiliser PgBouncer
L’application fonctionne via PgBouncer avec les paramètres par défaut d’asyncpg et de SQLAlchemy :- asyncpg exécute chaque requête sous forme de requête préparée nommée au niveau du protocole, et SQLAlchemy en met jusqu’à 100 en cache par connexion. Le PgBouncer fourni prend en charge ces requêtes en mode pool de connexions par transaction, et asyncpg les libère au moyen d’un message
Closeau niveau du protocole plutôt qu’avec la commande SQLDEALLOCATE. Vous n’avez donc besoin ni destatement_cache_size=0ni d’une fonctionprepared_statement_name_funcpersonnalisée. Si vous désactivez malgré tout le cache de requêtes d’asyncpg, ajoutez égalementprepared_statement_cache_size=0à l’URL pour désactiver le cache de SQLAlchemy. - Les paramètres de session définis avec
SET, commesearch_path, ne sont pas conservés d’une transaction à l’autre et peuvent fuiter vers d’autres clients. Utilisez plutôtSET LOCALà l’intérieur d’une transaction. pg_stat_sslrend compte de la connexion entre PgBouncer et Postgres ; la vérification TLS ci-dessus renvoie donc(False, None)via le port6432. La connexion de l’application à PgBouncer est pourtant bien vérifiée : un certificat de CA incorrect provoque le même échec.- Alembic ne pose pas de verrous consultatifs et exécute chaque
upgradedans une seule transaction ; il fonctionne donc lui aussi via PgBouncer. La connexion directe reste toutefois préférable pour les migrations longues.
Étapes suivantes
- Connexion : chaînes de connexion, PgBouncer et TLS
- Paramètres : paramètres de Postgres et de PgBouncer, comme
max_connections - Répliques en lecture : acheminer les requêtes en lecture seule vers une réplique dotée d’un second moteur
- Sécurité : listes d’accès IP et réseau privé