TypeScript DynamoDB
Este gerador cria um novo projeto TypeScript DynamoDB apoiado pelo Amazon DynamoDB, usando ElectroDB para modelagem de entidades com segurança de tipo. Ele gera o código da aplicação e a infraestrutura necessária para provisionar e gerenciar uma tabela DynamoDB usando AWS CDK ou Terraform, com suporte para design de tabela única e desenvolvimento local integrado via DynamoDB Local.
Gerar um Projeto TypeScript DynamoDB
Seção intitulada “Gerar um Projeto TypeScript DynamoDB”Execute este gerador@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- Instale o Nx Console VSCode Plugin se ainda não o fez
- Abra o console Nx no VSCode
- Clique em
Generate (UI)na seção "Common Nx Commands" - Procure por
@aws/nx-plugin - ts#dynamodb - Preencha os parâmetros obrigatórios
- Clique em
Generate
Monte seu comando8
Obrigatório
nameObrigatóriostringNome do projeto DynamoDB a ser gerado
directorystringPadrão:packagesO diretório onde armazenar o projeto.
frameworkenumPadrão:electrodbO framework a ser usado para entidades DynamoDB.
electrodbinfraenumPadrão:dynamodbInfraestrutura a provisionar para a tabela DynamoDB.
dynamodbnoneiacenumPadrão:inheritO provedor IaC preferido. Por padrão, isso é herdado da sua seleção inicial.
inheritcdkterraformsubDirectorystringO subdiretório onde o projeto é colocado. Por padrão, este é o nome do projeto.
tableNamestringO nome da tabela DynamoDB. Gerado automaticamente se não especificado.
preferInstallDependenciesbooleanPadrão:trueSe deve preferir instalar dependências após a execução do gerador. Defina como false para adiar a instalação ao executar múltiplos geradores em lote (uma instalação ainda é executada se necessário para que geradores subsequentes possam calcular o grafo de projetos Nx); instale uma vez no final.
Saída do Gerador
Seção intitulada “Saída do Gerador”O gerador cria a seguinte estrutura de projeto no diretório <directory>/<name>:
Directorysrc
- index.ts Project entry point and exports
- client.ts DynamoDB client singleton and table name resolution
Directoryentities
- 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
Os scripts de desenvolvimento local são compartilhados entre todos os projetos DynamoDB (tanto TypeScript quanto Python) e gerados uma vez em:
Directorypackages/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
Infraestrutura
Seção intitulada “Infraestrutura”Como este gerador fornece infraestrutura como código baseada no seu iac escolhido, ele criará um projeto em packages/common que inclui os constructs CDK relevantes ou módulos Terraform.
O projeto comum de infraestrutura como código é estruturado da seguinte forma:
Directorypackages/common/constructs
Directorysrc
Directoryapp/ Constructs for infrastructure specific to a project/generator
- …
Directorycore/ Generic constructs which are reused by constructs in
app- …
- index.ts Entry point exporting constructs from
app
- project.json Project build targets and configuration
Directorypackages/common/terraform
Directorysrc
Directoryapp/ Terraform modules for infrastructure specific to a project/generator
- …
Directorycore/ Generic modules which are reused by modules in
app- …
- project.json Project build targets and configuration
Directorypackages/common/constructs/src
Directoryapp
Directorydynamodb
- <name>.ts Infraestrutura específica para sua tabela
Directorycore
- dynamodb.ts Construto genérico de tabela DynamoDB
Directorypackages/common/terraform/src
Directoryapp
Directorydynamodb
Directory<name>
- <name>.tf Módulo específico para sua tabela
Directorycore
Directorydynamodb
- dynamodb.tf Módulo genérico DynamoDB
Arquitetura
Seção intitulada “Arquitetura”O projeto implantado provisiona a própria tabela, que qualquer projeto conectado a ela lê e escreve:
Desenvolvimento Local
Seção intitulada “Desenvolvimento Local”Iniciando o DynamoDB Local
Seção intitulada “Iniciando o DynamoDB Local”O gerador configura um target dev que inicia uma instância do DynamoDB Local e cria a tabela. Use o target dev do projeto:
pnpm nx dev <project-name>yarn nx dev <project-name>npx nx dev <project-name>bunx nx dev <project-name>Isso automaticamente:
- Baixa a imagem do DynamoDB Local (target
pull-image) - Inicia um container
- Cria uma tabela local com os índices definidos em
config.json
Modelagem de Dados
Seção intitulada “Modelagem de Dados”O projeto gerado usa ElectroDB para modelagem de entidades com segurança de tipo em uma única tabela DynamoDB, seguindo o design de tabela única do DynamoDB. Adicione ou atualize arquivos de entidade em src/entities/, usando a entidade de exemplo gerada como ponto de partida.
Exemplo de definição de entidade:
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() }, );Para mais detalhes, consulte a documentação de entidades do ElectroDB.
Usando o Cliente DynamoDB
Seção intitulada “Usando o Cliente DynamoDB”O src/client.ts gerado exporta dois utilitários principais:
getDynamoDBClient()— retorna um singletonDynamoDBClientem cache. QuandoLOCAL_DEV=true, conecta-se à instância local do DynamoDB Local; caso contrário, cria um cliente AWS usando a cadeia de credenciais padrão.resolveTableName()— retorna o nome da tabela DynamoDB. QuandoLOCAL_DEV=true, retorna a constante do nome da tabela local; caso contrário, busca o nome do AWS AppConfig usando a variável de ambienteRUNTIME_CONFIG_APP_IDe o armazena em cache para chamadas subsequentes.
Parando o DynamoDB Local
Seção intitulada “Parando o DynamoDB Local”Parar o dev (por exemplo, com Ctrl+C) remove automaticamente o contêiner DynamoDB Local, mas preserva o volume nomeado para que seus dados persistam entre reinicializações.
Adicionando/Removendo Índices Secundários Globais
Seção intitulada “Adicionando/Removendo Índices Secundários Globais”Os GSIs são definidos em config.json na raiz do projeto sob a chave tableConfig.globalSecondaryIndexes. Adicione uma entrada para cada GSI, seguindo a convenção de nomenclatura de chaves GSI do design de tabela única:
{ ... "tableConfig": { "globalSecondaryIndexes": [ { "indexName": "gsi1pk-gsi1sk-index", "partitionKey": "gsi1pk", "sortKey": "gsi1sk" }, { "indexName": "gsi2pk-gsi2sk-index", "partitionKey": "gsi2pk", "sortKey": "gsi2sk" } ] }}O campo sortKey é opcional para GSIs somente com chave de hash.
Este arquivo de configuração é a única fonte de verdade lida por todos os consumidores:
- Desenvolvimento local —
devlêconfig.jsone cria ou atualiza a tabela local para corresponder à lista de GSI - CDK — o construct lê
config.jsonno momento da síntese, então as mudanças de GSI são refletidas no próximocdk deploy - Terraform — o módulo lê
config.jsonno momento do plan/apply
Um GSI por Implantação
Seção intitulada “Um GSI por Implantação”Conectando-se à Tabela
Seção intitulada “Conectando-se à Tabela”Em qualquer projeto TypeScript, importe as fábricas de entidade do seu pacote DynamoDB e use-as diretamente:
import { createExampleEntity } from '@my-scope/my-table';
const entity = await createExampleEntity();const result = await entity.query.primary({ id: '123' }).go();Nos bastidores, createExampleEntity() chama resolveTableName() para buscar o nome da tabela do AWS AppConfig em tempo de execução.
Implantando sua Tabela
Seção intitulada “Implantando sua Tabela”O gerador DynamoDB cria infraestrutura CDK ou Terraform com base no seu iac selecionado.
O construto CDK é criado em common/constructs. Exemplo de uso:
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'); }}Isso provisiona uma tabela DynamoDB com:
pk(chave de partição) esk(chave de ordenação), ambas do tipoString- Índices Secundários Globais conforme definido em
config.json - Cobrança sob demanda (
PAY_PER_REQUEST) - Criptografia KMS gerenciada pelo cliente com rotação automática de chave
- Recuperação point-in-time habilitada
- Proteção contra exclusão habilitada
- Nome da tabela registrado no Runtime Config sob o namespace
dynamodbno AWS AppConfig
O módulo Terraform é criado em common/terraform. Exemplo de uso:
module "my_table" { source = "../../common/terraform/src/app/dynamodb/my-table"}Isso provisiona uma tabela DynamoDB com:
pk(chave de partição) esk(chave de ordenação), ambas do tipoString- Índices Secundários Globais conforme definido em
config.json - Cobrança sob demanda (
PAY_PER_REQUEST) - Criptografia KMS gerenciada pelo cliente com rotação automática de chave
- Recuperação point-in-time habilitada
- Proteção contra exclusão habilitada, além de uma proteção de ciclo de vida
prevent_destroy - Nome da tabela registrado no Runtime Config sob o namespace
dynamodbno AWS AppConfig
O módulo core/runtime-config/appconfig expõe o namespace dynamodb por padrão, então o nome da tabela é implantado sem configuração adicional. Se você passar namespaces para esse módulo explicitamente, mantenha dynamodb na lista — caso contrário, nenhum perfil de configuração é criado para ele e o cliente de tabela gerado não consegue resolver o nome da tabela.
Proteção contra Exclusão
Seção intitulada “Proteção contra Exclusão”A tabela é protegida por duas proteções independentes, de modo que desativar apenas uma delas não pode excluir seus dados:
deletionProtection, aplicada pelo DynamoDB.RemovalPolicy.RETAIN, aplicada pelo CloudFormation, que deixa a tabela no lugar quando ela é removida da stack.
deletion_protection_enabled, aplicada pelo DynamoDB.lifecycle { prevent_destroy = true }na tabela emcommon/terraform/src/core/dynamodb/dynamodb.tf, aplicada pelo Terraform, que falha qualquer plano que destruiria a tabela.
Excluindo a Tabela
Seção intitulada “Excluindo a Tabela”Desabilite a proteção para ambientes onde a exclusão da tabela é esperada, como stacks de desenvolvimento ou preview de curta duração.
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 deve ser um literal — o Terraform não permite que ele referencie uma variável — então não pode ser desativado a partir de main.tf. Remova também o bloco lifecycle da tabela em common/terraform/src/core/dynamodb/dynamodb.tf:
resource "aws_dynamodb_table" "table" { # ...
lifecycle { prevent_destroy = true }}Modo de Cobrança
Seção intitulada “Modo de Cobrança”A tabela usa por padrão cobrança sob demanda (PAY_PER_REQUEST). Mude para capacidade provisionada para cargas de trabalho previsíveis e de alto throughput.
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"}Recuperação Point-in-time
Seção intitulada “Recuperação Point-in-time”Recuperação point-in-time está habilitada por padrão, permitindo que você restaure a tabela para qualquer ponto nos últimos 35 dias.
Desabilitar Recuperação Point-in-time
Seção intitulada “Desabilitar Recuperação Point-in-time”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}Criptografia
Seção intitulada “Criptografia”A tabela é criptografada com uma chave KMS gerenciada pelo cliente por padrão, criada automaticamente para você. Mude para uma chave gerenciada pela AWS, a chave de propriedade da AWS, ou traga sua própria chave KMS, se você gerencia a criptografia de forma diferente.
Usar uma Chave Gerenciada pela AWS
Seção intitulada “Usar uma Chave Gerenciada pela AWS”Usa a chave KMS compartilhada aws/dynamodb que a AWS gerencia em seu nome. Ela é visível no console KMS da sua conta e cobrada por requisição, mas não há chave para você criar, rotacionar ou excluir.
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"}Usar a Chave de Propriedade da AWS
Seção intitulada “Usar a Chave de Propriedade da AWS”Usa uma chave totalmente de propriedade e gerenciada pela AWS — gratuita, sem chave visível em sua conta. A opção mais simples quando você não precisa de uma chave visível ao cliente ou à conta por motivos de conformidade.
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"}Mudando de CUSTOMER_MANAGED
Seção intitulada “Mudando de CUSTOMER_MANAGED”Em uma tabela já implantada, alterar encryption de CUSTOMER_MANAGED (para AWS_MANAGED ou DEFAULT) em um único terraform apply falha: o Terraform destrói a chave gerenciada pelo cliente antes de atualizar a tabela, e o DynamoDB então rejeita a atualização porque a chave já está pendente de exclusão.
Contorne isso atualizando a criptografia da tabela diretamente via AWS CLI primeiro, e depois deixando o Terraform alcançar e limpar a chave órfã:
# 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.StatusEntão atualize encryption em sua configuração Terraform e execute terraform apply normalmente — o Terraform agora só precisa destruir a chave já não utilizada, sem nada mais dependendo dela.
Usar Sua Própria Chave KMS
Seção intitulada “Usar Sua Própria Chave KMS”Forneça uma chave gerenciada pelo cliente existente em vez de ter uma criada para você. A chave já deve conceder ao serviço DynamoDB as permissões necessárias em sua própria política de chave.
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"}Rotação de Chave de Criptografia
Seção intitulada “Rotação de Chave de Criptografia”Quando a tabela cria sua própria chave KMS gerenciada pelo cliente (o padrão, e apenas quando você não forneceu sua própria chave), essa chave tem rotação automática de chave habilitada por padrão. Desabilite-a se sua política de segurança gerencia a rotação externamente.
Desabilitar Rotação de Chave de Criptografia
Seção intitulada “Desabilitar Rotação de Chave de Criptografia”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}Conexões
Seção intitulada “Conexões”Use o gerador connection para integrar este projeto com outros no seu workspace. As seguintes conexões envolvem este projeto: