TypeScript DynamoDB
此生成器创建一个新的 TypeScript DynamoDB 项目,由 Amazon DynamoDB 支持,使用 ElectroDB 进行类型安全的实体建模。它生成应用程序代码和基础设施,用于使用 AWS CDK 或 Terraform 配置和管理 DynamoDB 表,支持单表设计,并通过 DynamoDB Local 内置本地开发功能。
生成 TypeScript DynamoDB 项目
Section titled “生成 TypeScript DynamoDB 项目”运行此生成器@aws/nx-plugin:ts#dynamodb
pnpm nx g @aws/nx-plugin:ts#dynamodb yarn nx g @aws/nx-plugin:ts#dynamodb npx nx g @aws/nx-plugin:ts#dynamodb bunx nx g @aws/nx-plugin:ts#dynamodb- 安装 Nx Console VSCode Plugin 如果您尚未安装
- 在VSCode中打开Nx控制台
- 点击
Generate (UI)在"Common Nx Commands"部分 - 搜索
@aws/nx-plugin - ts#dynamodb - 填写必需参数
- 点击
Generate
构建你的命令8
必需
name必需string要生成的 DynamoDB 项目名称
directorystring默认值:packages存储项目的目录。
frameworkenum默认值:electrodb用于 DynamoDB 实体的框架。
electrodbinfraenum默认值:dynamodb为 DynamoDB 表配置的基础设施。
dynamodbnoneiacenum默认值:inherit首选的 IaC 提供商。默认情况下,这继承自您的初始选择。
inheritcdkterraformsubDirectorystring项目放置的子目录。默认情况下为项目名称。
tableNamestringDynamoDB 表名称。如果未指定则自动生成。
preferInstallDependenciesboolean默认值:true是否在生成器运行后优先安装依赖项。设置为 false 可在批量运行多个生成器时延迟安装(如果后续生成器需要计算 Nx 项目图,仍会运行安装);在最后统一安装一次。
生成器在 <directory>/<name> 目录中创建以下项目结构:
文件夹src
- index.ts Project entry point and exports
- client.ts DynamoDB client singleton and table name resolution
文件夹entities
- example.ts Example ElectroDB entity definition
- index.ts Entity exports
- config.json Table configuration including GSI definitions and local development settings
- package.json Project manifest defining the project’s package name and dependencies
- project.json Project configuration and build targets
本地开发脚本在所有 DynamoDB 项目(TypeScript 和 Python)之间共享,并生成一次到:
文件夹packages/common/scripts/src/dynamodb
- create-local-table.ts Creates the DynamoDB table in the local DynamoDB Local instance
- pull-image.ts Pulls the DynamoDB Local image
- start-container.ts Starts the DynamoDB Local container
由于此生成器根据您选择的 iac 提供基础设施即代码,它将在 packages/common 中创建一个项目,其中包含相关的 CDK 构造或 Terraform 模块。
通用基础设施即代码项目的结构如下:
文件夹packages/common/constructs
文件夹src
文件夹app/ Constructs for infrastructure specific to a project/generator
- …
文件夹core/ Generic constructs which are reused by constructs in
app- …
- index.ts Entry point exporting constructs from
app
- project.json Project build targets and configuration
文件夹packages/common/terraform
文件夹src
文件夹app/ Terraform modules for infrastructure specific to a project/generator
- …
文件夹core/ Generic modules which are reused by modules in
app- …
- project.json Project build targets and configuration
文件夹packages/common/constructs/src
文件夹app
文件夹dynamodb
- <name>.ts 特定于您的表的基础设施
文件夹core
- dynamodb.ts 通用 DynamoDB 表构造
文件夹packages/common/terraform/src
文件夹app
文件夹dynamodb
文件夹<name>
- <name>.tf 特定于您的表的模块
文件夹core
文件夹dynamodb
- dynamodb.tf 通用 DynamoDB 模块
部署的项目配置表本身,任何连接到它的项目都可以读取和写入:
启动本地 DynamoDB
Section titled “启动本地 DynamoDB”生成器配置了一个 dev 目标,用于启动 DynamoDB Local 实例并创建表。使用项目的 dev 目标:
pnpm nx dev <project-name>yarn nx dev <project-name>npx nx dev <project-name>bunx nx dev <project-name>这会自动:
- 拉取 DynamoDB Local 镜像(
pull-image目标) - 启动容器
- 使用
config.json中定义的索引创建本地表
生成的项目使用 ElectroDB 在单个 DynamoDB 表上进行类型安全的实体建模,遵循 DynamoDB 的单表设计。在 src/entities/ 下添加或更新实体文件,使用生成的示例实体作为起点。
示例实体定义:
import { Entity } from 'electrodb';import { getDynamoDBClient, resolveTableName } from '../client.js';
export const createExampleEntity = async () => new Entity( { model: { entity: 'example', version: '1', service: 'MyTable', }, attributes: { id: { type: 'string', required: true, }, createdAt: { type: 'string', required: true, default: () => new Date().toISOString(), readOnly: true, }, updatedAt: { type: 'string', required: true, default: () => new Date().toISOString(), watch: '*', set: () => new Date().toISOString(), }, }, indexes: { primary: { pk: { field: 'pk', composite: ['id'], }, sk: { field: 'sk', composite: [], }, }, }, }, { client: getDynamoDBClient(), table: await resolveTableName() }, );有关更多详细信息,请参阅 ElectroDB 实体文档。
使用 DynamoDB 客户端
Section titled “使用 DynamoDB 客户端”生成的 src/client.ts 导出两个关键实用程序:
getDynamoDBClient()— 返回一个缓存的单例DynamoDBClient。当LOCAL_DEV=true时,连接到本地 DynamoDB Local 实例;否则使用默认凭证链创建 AWS 客户端。resolveTableName()— 返回 DynamoDB 表名称。当LOCAL_DEV=true时,返回本地表名称常量;否则使用RUNTIME_CONFIG_APP_ID环境变量从 AWS AppConfig 获取名称,并将其缓存以供后续调用。
停止本地 DynamoDB
Section titled “停止本地 DynamoDB”停止 dev(例如使用 Ctrl+C)会自动删除 DynamoDB Local 容器,但会保留命名卷,因此您的数据在重启后仍然存在。
添加/删除全局二级索引
Section titled “添加/删除全局二级索引”GSI 在项目根目录的 config.json 中的 tableConfig.globalSecondaryIndexes 键下定义。为每个 GSI 添加一个条目,遵循 单表设计 的 GSI 键命名约定:
{ ... "tableConfig": { "globalSecondaryIndexes": [ { "indexName": "gsi1pk-gsi1sk-index", "partitionKey": "gsi1pk", "sortKey": "gsi1sk" }, { "indexName": "gsi2pk-gsi2sk-index", "partitionKey": "gsi2pk", "sortKey": "gsi2sk" } ] }}对于仅使用哈希键的 GSI,sortKey 字段是可选的。
此配置文件是所有使用者读取的单一事实来源:
- 本地开发 —
dev读取config.json并创建或更新本地表以匹配 GSI 列表 - CDK — 构造在合成时读取
config.json,因此 GSI 更改会在下次cdk deploy时反映出来 - Terraform — 模块在计划/应用时读取
config.json
每次部署一个 GSI
Section titled “每次部署一个 GSI”在任何 TypeScript 项目中,从您的 DynamoDB 包导入实体工厂并直接使用它们:
import { createExampleEntity } from '@my-scope/my-table';
const entity = await createExampleEntity();const result = await entity.query.primary({ id: '123' }).go();在幕后,createExampleEntity() 调用 resolveTableName() 在运行时从 AWS AppConfig 获取表名称。
DynamoDB 生成器根据您选择的 iac 创建 CDK 或 Terraform 基础设施。
CDK 构造在 common/constructs 中创建。使用示例:
import { MyTable } from '@my-scope/common-constructs';
export class ApplicationStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props);
const table = new MyTable(this, 'Table'); }}这将配置一个具有以下特性的 DynamoDB 表:
pk(分区键)和sk(排序键),均为String类型- 在
config.json中定义的全局二级索引 - 按需(
PAY_PER_REQUEST)计费 - 具有自动密钥轮换的客户托管 KMS 加密
- 启用时间点恢复
- 启用删除保护
- 表名在 AWS AppConfig 的
dynamodb命名空间下注册到 Runtime Config
Terraform 模块在 common/terraform 中创建。使用示例:
module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table"}这将配置一个具有以下特性的 DynamoDB 表:
pk(分区键)和sk(排序键),均为String类型- 在
config.json中定义的全局二级索引 - 按需(
PAY_PER_REQUEST)计费 - 具有自动密钥轮换的客户托管 KMS 加密
- 启用时间点恢复
- 启用删除保护,以及
prevent_destroy生命周期保护 - 表名在 AWS AppConfig 的
dynamodb命名空间下注册到 Runtime Config
core/runtime-config/appconfig 模块默认公开 dynamodb 命名空间,因此表名无需进一步配置即可部署。如果您显式地向该模块传递 namespaces,请在列表中保留 dynamodb —— 否则不会为其创建配置文件,生成的表客户端将无法解析表名。
表由两个独立的保护机制保护,因此单独关闭其中任何一个都无法删除您的数据:
deletionProtection,由 DynamoDB 强制执行。RemovalPolicy.RETAIN,由 CloudFormation 强制执行,当表从堆栈中移除时会将其保留在原处。
deletion_protection_enabled,由 DynamoDB 强制执行。lifecycle { prevent_destroy = true }在common/terraform/src/core/dynamodb/dynamodb.tf中的表上,由 Terraform 强制执行,会使任何试图销毁表的计划失败。
对于预期会删除表的环境(例如短期开发或预览堆栈),可以禁用保护。
import { RemovalPolicy } from 'aws-cdk-lib';import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', { deletionProtection: false, removalPolicy: RemovalPolicy.DESTROY,});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" deletion_protection_enabled = false}prevent_destroy 必须是字面量 —— Terraform 不允许它引用变量 —— 因此无法从 main.tf 中关闭它。还需要从 common/terraform/src/core/dynamodb/dynamodb.tf 中的表中删除 lifecycle 块:
resource "aws_dynamodb_table" "table" { # ...
lifecycle { prevent_destroy = true }}表默认使用按需(PAY_PER_REQUEST)计费。对于可预测的高吞吐量工作负载,可以切换到预配置容量。
import { BillingMode } from 'aws-cdk-lib/aws-dynamodb';import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', { billingMode: BillingMode.PROVISIONED, readCapacity: 5, writeCapacity: 5,});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" billing_mode = "PROVISIONED"}默认启用时间点恢复,允许您将表恢复到过去 35 天内的任何时间点。
禁用时间点恢复
Section titled “禁用时间点恢复”import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', { pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: false },});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" point_in_time_recovery_enabled = false}默认情况下,表使用客户托管的 KMS 密钥进行加密,该密钥会自动为您创建。如果您以不同方式管理加密,可以切换到 AWS 托管密钥、AWS 拥有的密钥或使用您自己的 KMS 密钥。
使用 AWS 托管密钥
Section titled “使用 AWS 托管密钥”使用 AWS 代表您管理的共享 aws/dynamodb KMS 密钥。它在您账户的 KMS 控制台中可见并按请求计费,但您无需创建、轮换或删除密钥。
import { TableEncryption } from 'aws-cdk-lib/aws-dynamodb';import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', { encryption: TableEncryption.AWS_MANAGED,});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" encryption = "AWS_MANAGED"}使用 AWS 拥有的密钥
Section titled “使用 AWS 拥有的密钥”使用完全由 AWS 拥有和管理的密钥——免费,且您的账户中完全看不到密钥。当您出于合规原因不需要客户或账户可见的密钥时,这是最简单的选项。
import { TableEncryption } from 'aws-cdk-lib/aws-dynamodb';import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', { encryption: TableEncryption.DEFAULT,});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" encryption = "DEFAULT"}从 CUSTOMER_MANAGED 切换
Section titled “从 CUSTOMER_MANAGED 切换”在已部署的表上,在单次 terraform apply 中将 encryption 从 CUSTOMER_MANAGED 更改为 AWS_MANAGED 或 DEFAULT 会失败:Terraform 在更新表之前销毁客户托管密钥,然后 DynamoDB 会拒绝更新,因为密钥已处于待删除状态。
解决方法是先通过 AWS CLI 直接更新表的加密,然后让 Terraform 跟进并清理孤立的密钥:
# For AWS_MANAGED:aws dynamodb update-table --table-name <table-name> \ --sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId=alias/aws/dynamodb
# For DEFAULT:aws dynamodb update-table --table-name <table-name> --sse-specification Enabled=false
# Then wait for this to report ENABLED (or for SSEDescription to disappear, for DEFAULT):aws dynamodb describe-table --table-name <table-name> --query Table.SSEDescription.Status然后在 Terraform 配置中更新 encryption 并正常运行 terraform apply——Terraform 现在只需要销毁已经未使用的密钥,没有任何东西依赖它。
使用您自己的 KMS 密钥
Section titled “使用您自己的 KMS 密钥”提供现有的客户托管密钥,而不是为您创建一个。该密钥必须在其自己的密钥策略中已经授予 DynamoDB 服务所需的权限。
import { Key } from 'aws-cdk-lib/aws-kms';import { MyTable } from '@my-scope/common-constructs';
const key = Key.fromKeyArn(this, 'Key', 'arn:aws:kms:us-east-1:111111111111:key/my-key-id');
const table = new MyTable(this, 'Table', { encryptionKey: key,});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" kms_key_arn = "arn:aws:kms:us-east-1:111111111111:key/my-key-id"}加密密钥轮换
Section titled “加密密钥轮换”当表创建自己的客户托管 KMS 密钥时(默认情况,且仅当您未提供自己的密钥时),该密钥默认启用自动密钥轮换。如果您的安全策略在外部管理轮换,可以禁用它。
禁用加密密钥轮换
Section titled “禁用加密密钥轮换”import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', { enableKeyRotation: false,});module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table" enable_key_rotation = false}使用 connection 生成器将此项目与工作区中的其他项目集成。以下连接涉及此项目: