在TypeScript CDK 2中配置AppSync将DynamoDB表名传入Lambda解析器
在TypeScript CDK 2中给AppSync Lambda解析器请求添加DynamoDB表名
核心思路
默认的appsync.MappingTemplate.lambdaRequest()生成的映射模板仅传递$ctx的JSON内容,要添加表名,需要自定义VTL请求模板,并通过CDK将表名注入模板中,这是最直接简便的实现方式。
具体实现步骤
1. 创建租户专属DynamoDB表
多租户场景下每个栈对应一个独立表,先完成表的定义:
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; import { Stack } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class TenantStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); // 租户专属DynamoDB表 const tenantTable = new dynamodb.Table(this, 'TenantTable', { partitionKey: { name: 'tenantId', type: dynamodb.AttributeType.STRING }, sortKey: { name: 'itemId', type: dynamodb.AttributeType.STRING }, billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, }); } }
2. 构建自定义Lambda请求映射模板
通过appsync.MappingTemplate.fromString()结合Fn.sub(),将表名注入到VTL模板中,保留原$ctx内容的同时新增tableName字段:
import * as appsync from 'aws-cdk-lib/aws-appsync'; import { Fn } from 'aws-cdk-lib'; // 假设已创建AppSync API和Lambda数据源 const api = new appsync.GraphqlApi(this, 'TenantApi', { name: 'TenantApi', schema: appsync.SchemaFile.fromAsset('schema.graphql'), }); const lambdaDataSource = api.addLambdaDataSource('TenantLambdaDs', tenantLambdaFunction); // 自定义请求模板:在payload中同时传递原context和表名 const customLambdaRequestTemplate = appsync.MappingTemplate.fromString(Fn.sub(` { "version": "2018-05-29", "operation": "Invoke", "payload": { "context": \$util.toJson(\$ctx), "tableName": "\${tableName}" } } `, { tableName: tenantTable.tableName }));
3. 配置解析器使用自定义模板
替换默认的lambdaRequest(),将自定义模板绑定到目标解析器:
// 为Query类型的getItem字段配置解析器 api.addResolver('GetItemResolver', { typeName: 'Query', fieldName: 'getItem', dataSource: lambdaDataSource, requestMappingTemplate: customLambdaRequestTemplate, responseMappingTemplate: appsync.MappingTemplate.lambdaResult(), // 保留默认响应模板 });
Lambda端接收参数
Lambda函数可直接从事件的payload中获取表名,无需额外配置环境变量:
import * as AWS from 'aws-sdk'; const dynamo = new AWS.DynamoDB.DocumentClient(); export const handler = async (event: any) => { const { tableName, context } = event; // 使用tableName操作对应租户的DynamoDB表 const result = await dynamo.get({ TableName: tableName, Key: { tenantId: context.arguments.tenantId, itemId: context.arguments.itemId, }, }).promise(); return result.Item; };
关键注意事项
- VTL中的
$符号在TypeScript模板字符串中需要用\$转义,避免被当作模板变量解析。 - 通过
Fn.sub()注入表名,能确保CDK部署时自动替换为带CloudFormation后缀的实际表名。 - 该方式无需依赖Lambda环境变量,表名随请求直接传递,更适配多租户栈的独立部署需求。
内容的提问来源于stack exchange,提问作者Setjmp
相关产品推荐
相关产品推荐

