跳转到内容

Smithy API 连接到关系数据库

connection 生成器将 Smithy API 连接到 关系数据库项目,将 Prisma 客户端注入到服务上下文中,以便所有操作实现都可以访问数据库。

在使用此生成器之前,请确保您拥有:

  1. 一个 ts#smithy-api 项目(TypeScript 后端)
  2. 一个 ts#rdb 项目
  1. 安装 Nx Console VSCode Plugin 如果您尚未安装
  2. 在VSCode中打开Nx控制台
  3. 点击 Generate (UI) 在"Common Nx Commands"部分
  4. 搜索 @aws/nx-plugin - connection
  5. 填写必需参数
    • 点击 Generate

    选择您的 Smithy API 后端项目作为源,选择您的关系数据库项目作为目标。

    参数 类型 默认值 描述
    sourceProject 必需 string - 源项目
    targetProject 必需 string - 要连接到的目标项目
    sourceComponent string - 要从其连接的源组件(组件名称、相对于源项目根目录的路径或生成器 ID)。使用 '.' 显式选择项目作为源。
    targetComponent string - 要连接到的目标组件(组件名称、相对于目标项目根目录的路径或生成器 ID)。使用 '.' 显式选择项目作为目标。

    生成器会修改 Smithy API 后端中的三个现有文件:

    • 文件夹packages/api/src
      • context.ts db 属性添加到 ServiceContext
      • handler.ts lambdaHandler 内创建 Prisma 客户端,传递给 serviceHandler.handle
      • local-server.ts 在请求处理程序内创建 Prisma 客户端,传递给 serviceHandler.handle

    此外,它还会更新 API 的 serve-local 目标以自动启动数据库。

    生成器在 context.ts 中向 ServiceContext 添加一个类型化的 db 属性:

    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>>;
    }

    Prisma 客户端在 lambdaHandler 内实例化,并通过服务上下文传递:

    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);
    };

    在操作实现中从上下文访问 db

    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 };
    };

    为了让您的 API 在运行时能够连接到数据库,API Lambda 函数必须部署到与数据库相同的 VPC 中,并被授予网络和 IAM 访问权限。

    在您的应用程序堆栈中,将 API 部署到与数据库相同的 VPC 中,然后调用 allowDefaultPortFromgrantConnect 来打开网络路径并为每个 Lambda 处理程序授予 IAM rds-db:connect 权限:

    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);
    });

    将 API Lambda 函数部署到具有出口的私有子网中,而不是私有隔离子网。在运行时,getPrisma() 从 AWS AppConfig 检索数据库连接详细信息,这是一个需要出站互联网访问的公共 AWS 服务端点。

    生成器在 local-server.ts 的请求处理程序内应用相同的 Prisma 客户端注入:

    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>

    这将同时启动 API 和本地数据库。SERVE_LOCAL=true 环境变量会自动设置,因此 Prisma 客户端会连接到本地 Docker 数据库而不是 Aurora。