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

Esegui questo generatore@aws/nx-plugin:connection

pnpm nx g @aws/nx-plugin:connection
Componi il tuo comando5

Obbligatorio

Obbligatorio

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

Opzioni del generatore5 opzioni
sourceProjectObbligatoriostring

Il progetto sorgente

targetProjectObbligatoriostring

Il progetto di destinazione a cui connettersi

sourceComponentstring

Il componente sorgente da cui connettersi (nome del componente, percorso relativo alla radice del progetto sorgente, o id del generatore). Usa '.' per selezionare esplicitamente il progetto come sorgente.

targetComponentstring

Il componente destinazione a cui connettersi (nome del componente, percorso relativo alla radice del progetto destinazione, o id del generatore). Usa '.' per selezionare esplicitamente il progetto come destinazione.

preferInstallDependenciesbooleanPredefinito: true

Se 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 e lo aggiunge al contesto tRPC:

  • Directorypackages/api/src
    • Directorymiddleware
      • <db-name>.ts plugin tRPC che espone il client Prisma nel contesto delle procedure
    • init.ts L’interfaccia di contesto del database aggiunta a Context

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 dbProcedure = 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 { dbProcedure } from '../router.js';
export const listUsers = dbProcedure
.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.