Salta ai contenuti

API Smithy a Database Relazionale

Il generatore connection collega un’API Smithy a un progetto Database Relazionale, iniettando un client Prisma nel contesto del servizio in modo che tutte le implementazioni delle operazioni possano accedere al database.

Prima di utilizzare questo generatore, assicurati di avere:

  1. Un progetto ts#smithy-api (backend TypeScript)
  2. Un progetto ts#rdb
  1. Installa il Nx Console VSCode Plugin se non l'hai già fatto
  2. Apri la console Nx in VSCode
  3. Clicca su Generate (UI) nella sezione "Common Nx Commands"
  4. Cerca @aws/nx-plugin - connection
  5. Compila i parametri richiesti
    • Clicca su Generate

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

    Parametro Tipo Predefinito Descrizione
    sourceProject Obbligatorio string - Il progetto sorgente
    targetProject Obbligatorio string - 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.

    Il generatore modifica tre file esistenti nel tuo backend API Smithy:

    • Directorypackages/api/src
      • context.ts proprietà db aggiunta a ServiceContext
      • handler.ts client Prisma creato all’interno di lambdaHandler, passato a serviceHandler.handle
      • local-server.ts client Prisma creato all’interno del gestore delle richieste, passato a serviceHandler.handle

    Inoltre, aggiorna il target serve-local dell’API per avviare automaticamente il database.

    Il generatore aggiunge una proprietà db tipizzata a ServiceContext in context.ts:

    packages/api/src/context.ts
    import { getPrisma as getMyDb } from ':my-scope/my-db';
    export interface ServiceContext {
    tracer: Tracer;
    logger: Logger;
    metrics: Metrics;
    myDb: Awaited<ReturnType<typeof getMyDb>>;
    }

    Il client Prisma viene istanziato all’interno di lambdaHandler e passato attraverso il contesto del servizio:

    packages/api/src/handler.ts
    import { getPrisma as getMyDb } from ':my-scope/my-db';
    export const lambdaHandler = async (event: APIGatewayProxyEvent) => {
    const httpRequest = convertEvent(event);
    const myDb = await getMyDb();
    const httpResponse = await serviceHandler.handle(httpRequest, {
    tracer,
    logger,
    metrics,
    myDb,
    });
    return convertVersion1Response(httpResponse);
    };

    Accedi a db dal contesto nelle tue implementazioni delle operazioni:

    packages/api/src/operations/list-users.ts
    import { ListUsersOperationInput, ListUsersOperationOutput } from '../generated/ssdk/index.js';
    import { ServiceContext } from '../context.js';
    export const listUsers = async (
    input: ListUsersOperationInput,
    ctx: ServiceContext,
    ): Promise<ListUsersOperationOutput> => {
    const users = await ctx.myDb.user.findMany();
    return { users };
    };

    Per consentire alla tua API di connettersi al database a 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 applicativo, 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. A runtime, getPrisma() recupera i dettagli di connessione al database da AWS AppConfig, che è un endpoint pubblico del servizio AWS che richiede accesso internet in uscita.

    Il generatore applica la stessa iniezione del client Prisma all’interno del gestore delle richieste in local-server.ts:

    packages/api/src/local-server.ts
    import { getPrisma as getMyDb } from ':my-scope/my-db';
    const server = createServer(async function (req, res) {
    const httpRequest = convertRequest(req);
    const myDb = await getMyDb();
    const httpResponse = await serviceHandler.handle(httpRequest, {
    tracer,
    logger,
    metrics,
    myDb,
    });
    return writeResponse(httpResponse, res);
    });
    Terminal window
    pnpm nx serve-local <api-project-name>

    Questo avvia sia l’API che il database locale. La variabile d’ambiente SERVE_LOCAL=true viene impostata automaticamente, in modo che il client Prisma si connetta al database Docker locale invece di Aurora.