API tRPC vers Base de Données Relationnelle
Le générateur connection connecte une API tRPC à un projet de Base de Données Relationnelle, en générant un plugin middleware tRPC type-safe qui rend un client Prisma disponible dans le contexte de vos procédures.
Prérequis
Section intitulée « Prérequis »Avant d’utiliser ce générateur, assurez-vous d’avoir :
- Un projet
ts#trpc-api - Un projet
ts#rdb
Utilisation
Section intitulée « Utilisation »Exécuter le Générateur
Section intitulée « Exécuter le Générateur »- Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
- Ouvrez la console Nx dans VSCode
- Cliquez sur
Generate (UI)dans la section "Common Nx Commands" - Recherchez
@aws/nx-plugin - connection - Remplissez les paramètres requis
- Cliquez sur
Generate
pnpm nx g @aws/nx-plugin:connectionyarn nx g @aws/nx-plugin:connectionnpx nx g @aws/nx-plugin:connectionbunx nx g @aws/nx-plugin:connectionVous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
pnpm nx g @aws/nx-plugin:connection --dry-runyarn nx g @aws/nx-plugin:connection --dry-runnpx nx g @aws/nx-plugin:connection --dry-runbunx nx g @aws/nx-plugin:connection --dry-runSélectionnez votre projet d’API tRPC comme source et votre projet de base de données relationnelle comme cible.
| Paramètre | Type | Par défaut | Description |
|---|---|---|---|
| sourceProject Requis | string | - | Le projet source |
| targetProject Requis | string | - | Le projet cible auquel se connecter |
| sourceComponent | string | - | Le composant source depuis lequel se connecter (nom du composant, chemin relatif à la racine du projet source, ou identifiant du générateur). Utilisez '.' pour sélectionner explicitement le projet comme source. |
| targetComponent | string | - | Le composant cible auquel se connecter (nom du composant, chemin relatif à la racine du projet cible, ou identifiant du générateur). Utilisez '.' pour sélectionner explicitement le projet comme cible. |
Sortie du Générateur
Section intitulée « Sortie du Générateur »Le générateur crée un fichier middleware dans votre projet d’API tRPC :
Répertoirepackages/api/src
Répertoiremiddleware
- <db-name>.ts Plugin tRPC exposant le client Prisma dans le contexte de procédure
De plus, il met à jour la cible serve-local de votre API tRPC pour démarrer automatiquement la base de données lors de l’exécution locale.
Utilisation du Middleware
Section intitulée « Utilisation du Middleware »Enregistrer le Plugin
Section intitulée « Enregistrer le Plugin »Ajoutez le plugin généré à votre routeur tRPC afin que toutes les procédures qui l’utilisent aient accès à la base de données :
import { t } from './init.js';import { createMyDbPlugin } from './middleware/my-db.js';
export const authenticatedProcedure = t.procedure .concat(createMyDbPlugin());Accéder à la Base de Données dans les Procédures
Section intitulée « Accéder à la Base de Données dans les Procédures »Le plugin fusionne IMyDbContext dans le contexte de votre procédure, rendant myDb disponible en tant que propriété optionnelle :
import { z } from 'zod';import { authenticatedProcedure } from '../router.js';
export const listUsers = authenticatedProcedure .output(z.array(z.object({ id: z.string(), name: z.string() }))) .query(async ({ ctx }) => { // ctx.myDb est le client Prisma — typé comme Awaited<ReturnType<typeof getPrisma>> return await ctx.myDb!.user.findMany(); });MySQL : Déconnexion Après Chaque Requête
Section intitulée « MySQL : Déconnexion Après Chaque Requête »Lorsque la base de données cible utilise le moteur MySQL, le middleware généré enveloppe opts.next() dans un bloc try/finally qui appelle $disconnect() :
return t.procedure.use(async (opts) => { const myDb = await getPrisma(); try { return await opts.next({ ctx: { ...opts.ctx, myDb } }); } finally { await myDb.$disconnect(); }});Cela résout le problème de l’adaptateur MySQL qui maintient la boucle d’événements Node.js ouverte après une requête, ce qui empêcherait autrement Lambda de vider les réponses en streaming. La déconnexion dans finally libère la boucle d’événements afin que la réponse puisse se terminer. Voir MySQL : Mode Streaming API Gateway pour plus de détails.
PostgreSQL ne nécessite pas cela — son adaptateur utilise un pool de connexions configuré avec allowExitOnIdle: true.
Bases de Données Multiples
Section intitulée « Bases de Données Multiples »Vous pouvez connecter des bases de données supplémentaires en exécutant à nouveau le générateur avec une cible différente. Chaque base de données obtient son propre plugin et interface de contexte :
export const dbProcedure = t.procedure .concat(createPostgresDbPlugin()) .concat(createMySqlDbPlugin());Infrastructure
Section intitulée « Infrastructure »Pour permettre à votre API de se connecter à la base de données lors de l’exécution, les fonctions Lambda de l’API doivent être déployées dans le même VPC que la base de données et bénéficier d’un accès réseau et IAM.
Dans votre stack d’application, déployez l’API dans le même VPC que la base de données, puis appelez allowDefaultPortFrom et grantConnect pour ouvrir le chemin réseau et accorder la permission IAM rds-db:connect à chaque gestionnaire Lambda :
import { MyDatabase } from ':my-scope/common-constructs';
const db = new MyDatabase(this, 'Db', { vpc, ... });
const api = new MyApi(this, 'Api', { integrations: MyApi.defaultIntegrations(this) .withDefaultOptions({ vpc, vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS }, }) .build(),});
Object.entries(api.integrations).forEach(([operation, integration]) => { db.allowDefaultPortFrom(integration.handler, `Allow ${operation} to connect to the database`); db.grantConnect(integration.handler);});Déployez les fonctions Lambda de l’API dans un sous-réseau privé avec sortie, et non dans un sous-réseau privé isolé. Lors de l’exécution, getPrisma() récupère les détails de connexion à la base de données depuis AWS AppConfig, qui est un point de terminaison de service AWS public nécessitant un accès Internet sortant.
Transmettez les sorties du module de base de données à votre module API afin qu’il puisse atteindre la base de données et lire sa configuration d’exécution :
module "my_database" { source = "../../common/terraform/src/app/dbs/my-database" vpc_id = module.vpc.vpc_id database_subnet_ids = module.vpc.private_isolated_subnet_ids lambda_subnet_ids = module.vpc.private_subnet_ids}
module "api" { source = "..." vpc_id = module.vpc.vpc_id private_subnet_ids = module.vpc.private_subnet_ids
appconfig_application_id = module.my_database.appconfig_application_id database_cluster_resource_id = module.my_database.cluster_resource_id database_runtime_user = module.my_database.database_runtime_user database_security_group_id = module.my_database.security_group_id database_port = module.my_database.cluster_port
environment_variables = { RUNTIME_CONFIG_APP_ID = module.my_database.appconfig_application_id }}Déployez les fonctions Lambda de l’API dans des sous-réseaux privés avec sortie, et non dans des sous-réseaux privés isolés. Assurez-vous que le rôle Lambda de l’API dispose de la permission rds-db:connect et que son groupe de sécurité peut atteindre le groupe de sécurité de la base de données sur le port de la base de données.
Développement Local
Section intitulée « Développement Local »Le générateur configure la cible serve-local de votre API tRPC pour dépendre de la cible serve-local de la base de données, donc l’exécution de :
pnpm nx serve-local <api-project-name>yarn nx serve-local <api-project-name>npx nx serve-local <api-project-name>bunx nx serve-local <api-project-name>démarrera automatiquement la base de données locale en même temps que votre API.