Aller au contenu

TypeScript DynamoDB

Ce générateur crée un nouveau projet TypeScript DynamoDB soutenu par Amazon DynamoDB, utilisant ElectroDB pour la modélisation d’entités type-safe. Il génère le code d’application et l’infrastructure nécessaires pour provisionner et gérer une table DynamoDB en utilisant AWS CDK ou Terraform, avec prise en charge de la conception à table unique et développement local intégré via DynamoDB Local.

Exécuter ce générateur@aws/nx-plugin:ts#dynamodb

pnpm nx g @aws/nx-plugin:ts#dynamodb
Composez votre commande8

Requis

Options du générateur8 options
nameRequisstring

Nom du projet DynamoDB à générer

directorystringPar défaut: packages

Le répertoire dans lequel stocker le projet.

frameworkenumPar défaut: electrodb

Le framework à utiliser pour les entités DynamoDB.

electrodb
infraenumPar défaut: dynamodb

Infrastructure à provisionner pour la table DynamoDB.

dynamodbnone
iacenumPar défaut: inherit

Le fournisseur IaC préféré. Par défaut, celui-ci est hérité de votre sélection initiale.

inheritcdkterraform
subDirectorystring

Le sous-répertoire dans lequel le projet est placé. Par défaut, il s'agit du nom du projet.

tableNamestring

Le nom de la table DynamoDB. Généré automatiquement si non spécifié.

preferInstallDependenciesbooleanPar défaut: true

Indique s'il faut privilégier l'installation des dépendances après l'exécution du générateur. Définir sur false pour différer l'installation lors de l'exécution de plusieurs générateurs en lot (une installation s'exécute quand même si nécessaire pour que les générateurs suivants puissent calculer le graphe de projet Nx) ; installer une seule fois à la fin.

Le générateur crée la structure de projet suivante dans le répertoire <directory>/<name> :

  • Répertoiresrc
    • index.ts Point d’entrée du projet et exports
    • client.ts Singleton du client DynamoDB et résolution du nom de table
    • Répertoireentities
      • example.ts Exemple de définition d’entité ElectroDB
      • index.ts Exports des entités
  • config.json Configuration de la table incluant les définitions GSI et les paramètres de développement local
  • package.json Manifeste du projet définissant le nom du package et les dépendances
  • project.json Configuration du projet et cibles de build

Les scripts de développement local sont partagés entre tous les projets DynamoDB (TypeScript et Python) et générés une fois dans :

  • Répertoirepackages/common/scripts/src/dynamodb
    • create-local-table.ts Crée la table DynamoDB dans l’instance DynamoDB Local locale
    • pull-image.ts Récupère l’image DynamoDB Local
    • start-container.ts Démarre le conteneur DynamoDB Local

Étant donné que ce générateur fournit de l’infrastructure en tant que code basée sur votre iac choisi, il créera un projet dans packages/common qui inclut les constructs CDK ou modules Terraform pertinents.

Le projet d’infrastructure en tant que code commun est structuré comme suit :

  • Répertoirepackages/common/constructs
    • Répertoiresrc
      • Répertoireapp/ Constructs pour l’infrastructure spécifique à un projet/générateur
      • Répertoirecore/ Constructs génériques qui sont réutilisés par les constructs dans app
      • index.ts Entry point exporting constructs from app
    • project.json Project build targets and configuration
  • Répertoirepackages/common/constructs/src
    • Répertoireapp
      • Répertoiredynamodb
        • <name>.ts Infrastructure spécifique à votre table
    • Répertoirecore
      • dynamodb.ts Construct générique de table DynamoDB

Le projet déployé provisionne la table elle-même, que tout projet auquel il est connecté lit et écrit :

Loading the diagram…

Le générateur configure une cible dev qui démarre une instance DynamoDB Local et crée la table. Utilisez la cible dev du projet :

Terminal window
pnpm nx dev <project-name>

Cela effectue automatiquement :

  1. Télécharge l’image DynamoDB Local (cible pull-image)
  2. Démarre un conteneur
  3. Crée une table locale avec les index définis dans config.json

Le projet généré utilise ElectroDB pour la modélisation d’entités type-safe sur une seule table DynamoDB, suivant la conception à table unique de DynamoDB. Ajoutez ou mettez à jour les fichiers d’entités sous src/entities/, en utilisant l’exemple d’entité généré comme point de départ.

Exemple de définition d’entité :

packages/my-table/src/entities/example.ts
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() },
);

Pour plus de détails, consultez la documentation des entités ElectroDB.

Le fichier src/client.ts généré exporte deux utilitaires clés :

  • getDynamoDBClient() — retourne un singleton DynamoDBClient en cache. Lorsque LOCAL_DEV=true, se connecte à l’instance DynamoDB Local locale ; sinon crée un client AWS utilisant la chaîne de credentials par défaut.
  • resolveTableName() — retourne le nom de la table DynamoDB. Lorsque LOCAL_DEV=true, retourne la constante du nom de table locale ; sinon récupère le nom depuis AWS AppConfig en utilisant la variable d’environnement RUNTIME_CONFIG_APP_ID et le met en cache pour les appels suivants.

L’arrêt de dev (par exemple avec Ctrl+C) supprime automatiquement le conteneur DynamoDB Local, mais préserve le volume nommé afin que vos données persistent entre les redémarrages.

Les GSI sont définis dans config.json à la racine du projet sous la clé tableConfig.globalSecondaryIndexes. Ajoutez une entrée pour chaque GSI, en suivant la convention de nommage de conception à table unique pour les clés GSI :

config.json
{
...
"tableConfig": {
"globalSecondaryIndexes": [
{
"indexName": "gsi1pk-gsi1sk-index",
"partitionKey": "gsi1pk",
"sortKey": "gsi1sk"
},
{
"indexName": "gsi2pk-gsi2sk-index",
"partitionKey": "gsi2pk",
"sortKey": "gsi2sk"
}
]
}
}

Le champ sortKey est optionnel pour les GSI avec clé de hachage uniquement.

Ce fichier de configuration est la source unique de vérité lue par tous les consommateurs :

  • Développement localdev lit config.json et crée ou met à jour la table locale pour correspondre à la liste des GSI
  • CDK — le construct lit config.json au moment de la synthèse, donc les modifications de GSI sont reflétées lors du prochain cdk deploy
  • Terraform — le module lit config.json au moment du plan/apply

Dans n’importe quel projet TypeScript, importez les factories d’entités depuis votre package DynamoDB et utilisez-les directement :

import { createExampleEntity } from '@my-scope/my-table';
const entity = await createExampleEntity();
const result = await entity.query.primary({ id: '123' }).go();

En coulisses, createExampleEntity() appelle resolveTableName() pour récupérer le nom de la table depuis AWS AppConfig au moment de l’exécution.

Le générateur DynamoDB crée une infrastructure CDK ou Terraform en fonction de votre iac sélectionné.

Le construct CDK est créé dans common/constructs. Exemple d’utilisation :

packages/infra/src/stacks/application-stack.ts
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');
}
}

Cela provisionne une table DynamoDB avec :

  • pk (clé de partition) et sk (clé de tri), toutes deux de type String
  • Des index secondaires globaux tels que définis dans config.json
  • Une facturation à la demande (PAY_PER_REQUEST)
  • Un chiffrement KMS géré par le client avec rotation automatique des clés
  • La récupération à un instant dans le passé activée
  • La protection contre la suppression activée
  • Le nom de la table enregistré dans Runtime Config sous l’espace de noms dynamodb dans AWS AppConfig

La table est protégée par deux gardes indépendantes, de sorte que la désactivation de l’une seule ne peut pas supprimer vos données :

  • deletionProtection, appliquée par DynamoDB.
  • RemovalPolicy.RETAIN, appliquée par CloudFormation, qui laisse la table en place lorsqu’elle est retirée de la stack.

Désactivez la protection pour les environnements où la suppression de table est attendue, comme les stacks de développement ou de prévisualisation éphémères.

packages/infra/src/stacks/application-stack.ts
import { RemovalPolicy } from 'aws-cdk-lib';
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
deletionProtection: false,
removalPolicy: RemovalPolicy.DESTROY,
});

La table utilise par défaut la facturation à la demande (PAY_PER_REQUEST). Passez à la capacité provisionnée pour des charges de travail prévisibles à haut débit.

packages/infra/src/stacks/application-stack.ts
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,
});

La récupération à un instant dans le passé est activée par défaut, vous permettant de restaurer la table à n’importe quel moment des 35 derniers jours.

Désactiver la récupération à un instant dans le passé

Section intitulée « Désactiver la récupération à un instant dans le passé »
packages/infra/src/stacks/application-stack.ts
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: false },
});

La table est chiffrée avec une clé KMS gérée par le client par défaut, créée automatiquement pour vous. Passez à une clé gérée par AWS, à la clé détenue par AWS, ou apportez votre propre clé KMS, si vous gérez le chiffrement différemment.

Utilise la clé KMS partagée aws/dynamodb qu’AWS gère en votre nom. Elle est visible dans la console KMS de votre compte et facturée par requête, mais il n’y a pas de clé à créer, faire pivoter ou supprimer.

packages/infra/src/stacks/application-stack.ts
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,
});

Utilise une clé entièrement détenue et gérée par AWS — gratuite, sans clé visible dans votre compte. L’option la plus simple lorsque vous n’avez pas besoin d’une clé visible par le client ou le compte pour des raisons de conformité.

packages/infra/src/stacks/application-stack.ts
import { TableEncryption } from 'aws-cdk-lib/aws-dynamodb';
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
encryption: TableEncryption.DEFAULT,
});
iac = terraform

Sur une table déjà déployée, changer encryption de CUSTOMER_MANAGED (vers AWS_MANAGED ou DEFAULT) en un seul terraform apply échoue : Terraform détruit la clé gérée par le client avant de mettre à jour la table, et DynamoDB rejette alors la mise à jour car la clé est déjà en attente de suppression.

Contournez ce problème en mettant à jour le chiffrement de la table directement via l’AWS CLI d’abord, puis en laissant Terraform rattraper son retard et nettoyer la clé orpheline :

Fenêtre de terminal
# 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

Ensuite, mettez à jour encryption dans votre configuration Terraform et exécutez terraform apply normalement — Terraform n’a maintenant besoin que de détruire la clé déjà inutilisée, sans rien qui en dépende.

Fournissez une clé gérée par le client existante au lieu d’en faire créer une pour vous. La clé doit déjà accorder au service DynamoDB les permissions dont il a besoin dans sa propre politique de clé.

packages/infra/src/stacks/application-stack.ts
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,
});

Lorsque la table crée sa propre clé KMS gérée par le client (par défaut, et uniquement lorsque vous n’avez pas fourni votre propre clé), cette clé a la rotation automatique activée par défaut. Désactivez-la si votre politique de sécurité gère la rotation en externe.

packages/infra/src/stacks/application-stack.ts
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
enableKeyRotation: false,
});

Utilisez le générateur connection pour intégrer ce projet avec d’autres dans votre workspace. Les connexions suivantes impliquent ce projet :

tRPCAmazon DynamoDB
tRPC API to TypeScript DynamoDBConnecter une API tRPC à une table DynamoDB
SmithyAmazon DynamoDB
Smithy API to TypeScript DynamoDBConnecter une API Smithy à une table DynamoDB
Strands AgentsTypeScriptAmazon DynamoDB
TypeScript Agent to TypeScript DynamoDBConnecter un TypeScript Agent à une table DynamoDB
Model Context ProtocolAmazon DynamoDB
MCP Server to TypeScript DynamoDBConnecter un TypeScript MCP Server à une table DynamoDB