Salta ai contenuti

API tRPC a Database Relazionale

Il generatore connection collega un’API tRPC a un progetto Database Relazionale, generando un plugin middleware tRPC type-safe che rende disponibile un client Prisma nel contesto delle tue procedure.

Prima di utilizzare questo generatore, assicurati di avere:

  1. Un progetto API tRPC (generato con ts#api)
  2. Un progetto ts#rdb
Terminal window
pnpm nx g @aws/nx-plugin:connection
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
Terminal window
pnpm nx g @aws/nx-plugin:connection --dry-run

Seleziona il tuo progetto API tRPC come sorgente e il tuo progetto database relazionale come destinazione.

ParametroTipoPredefinitoDescrizione
sourceProject Obbligatoriostring-Il progetto sorgente
targetProject Obbligatoriostring-Il progetto di destinazione a cui connettersi
sourceComponent string-Il componente sorgente da cui connettersi (nome del componente, percorso relativo alla radice del progetto sorgente, o id del generatore). Usare '.' per selezionare esplicitamente il progetto come sorgente.
targetComponent string-Il componente di destinazione a cui connettersi (nome del componente, percorso relativo alla radice del progetto di destinazione, o id del generatore). Usare '.' per selezionare esplicitamente il progetto come destinazione.
preferInstallDependencies booleantrueSe preferire l'installazione delle dipendenze dopo l'esecuzione del generatore. Impostare su false per rimandare l'installazione quando si eseguono più generatori in batch (l'installazione viene comunque eseguita se necessaria affinché i generatori successivi possano calcolare il grafo dei progetti Nx); installare una volta alla fine.

Il generatore crea un file middleware nel tuo progetto API tRPC:

  • Directorypackages/api/src
    • Directorymiddleware
      • <db-name>.ts plugin tRPC che espone il client Prisma nel contesto delle procedure

Inoltre, aggiorna il target dev della tua API tRPC per avviare automaticamente il database quando viene eseguito localmente.

Aggiungi il plugin generato al tuo router tRPC in modo che tutte le procedure che lo utilizzano ottengano accesso al database:

packages/api/src/router.ts
import { t } from './init.js';
import { createMyDbPlugin } from './middleware/my-db.js';
export const authenticatedProcedure = t.procedure
.concat(createMyDbPlugin());

Il plugin unisce IMyDbContext nel contesto delle tue procedure, rendendo myDb disponibile come proprietà opzionale:

packages/api/src/procedures/users.ts
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 is the Prisma client — typed as Awaited<ReturnType<typeof getPrisma>>
return await ctx.myDb!.user.findMany();
});

Quando il database di destinazione utilizza il motore MySQL, il middleware generato avvolge opts.next() in un blocco try/finally che chiama $disconnect():

packages/api/src/middleware/my-db.ts
return t.procedure.use(async (opts) => {
const myDb = await getPrisma();
try {
return await opts.next({ ctx: { ...opts.ctx, myDb } });
} finally {
await myDb.$disconnect();
}
});

Questo risolve il problema dell’adapter MySQL che mantiene aperto il ciclo degli eventi di Node.js dopo una query, il che altrimenti impedirebbe a Lambda di svuotare le risposte in streaming. Disconnettersi in finally rilascia il ciclo degli eventi in modo che la risposta possa completarsi. Vedi MySQL: API Gateway Streaming Mode per i dettagli.

PostgreSQL non richiede questo — il suo adapter utilizza un pool di connessioni configurato con allowExitOnIdle: true.

Puoi connettere database aggiuntivi eseguendo nuovamente il generatore con una destinazione diversa. Ogni database ottiene il proprio plugin e interfaccia di contesto:

packages/api/src/router.ts
export const dbProcedure = t.procedure
.concat(createMyDbPlugin())
.concat(createOtherDbPlugin());

Per consentire alla tua API di connettersi al database in fase di runtime, le funzioni Lambda dell’API devono essere distribuite nello stesso VPC del database e devono avere accesso di rete e IAM.

Nel tuo stack dell’applicazione, distribuisci l’API nello stesso VPC del database, quindi chiama allowDefaultPortFrom e grantConnect per aprire il percorso di rete e concedere il permesso IAM rds-db:connect a ciascun handler Lambda:

packages/infra/src/stacks/application-stack.ts
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);
});

Distribuisci le funzioni Lambda dell’API in una subnet privata con egress, non in una subnet privata isolata. In fase di runtime, getPrisma() recupera i dettagli di connessione al database da AWS AppConfig, che è un endpoint di servizio AWS pubblico che richiede accesso a Internet in uscita.

Requisiti SSL Quando ci si Connette Senza RDS Proxy

Sezione intitolata “Requisiti SSL Quando ci si Connette Senza RDS Proxy”

Per le connessioni dirette al cluster Aurora dai runtime Lambda Node.js 20 o successivi, caricare il bundle CA di Amazon RDS impostando NODE_EXTRA_CA_CERTS:

packages/infra/src/stacks/application-stack.ts
const api = new Api(this, 'Api', {
integrations: Api.defaultIntegrations(this)
.withDefaultOptions({
environment: {
NODE_EXTRA_CA_CERTS: '/var/runtime/ca-cert.pem',
},
})
.build(),
});

Per maggiori dettagli, consultare i requisiti SSL/TLS per le connessioni Amazon RDS di AWS Lambda e la documentazione TLS di Amazon RDS Proxy. Quando si utilizza RDS Proxy, non è necessario configurare il bundle CA di RDS nella funzione Lambda.

Il generatore configura il target dev della tua API tRPC per dipendere dal target dev del database, quindi eseguendo:

Terminal window
pnpm nx dev <api-project-name>

avvierà automaticamente il database locale insieme alla tua API.