如何无需新建类拆分AWS CDK TypeScript Stack构造函数资源?
实现方案
完全可以在不新建Construct类的前提下,按资源类型拆分逻辑到独立文件,符合CDK的通用组织范式。
核心逻辑非常简单:CDK中所有资源构造的第一个参数是资源挂载的父scope(也就是Stack类内的this),只要把这个scope作为入参传给独立文件的普通工厂函数,就能正常完成资源创建,不需要为每类资源单独编写继承自Construct的自定义类。
具体拆分步骤
1. 拆分DynamoDB表定义到独立文件
新建src/resources/dynamo-table.ts,导出创建表的普通函数:
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; import { Construct } from 'constructs'; export function createItemsDynamoTable(scope: Construct) { return new dynamodb.Table(scope, "items", { partitionKey: { name: "itemId", type: dynamodb.AttributeType.STRING }, tableName: "items" }); }
2. 拆分Lambda定义到独立文件
新建src/resources/lambdas.ts,集中管理所有Lambda的创建、权限绑定逻辑,入参传入需要依赖的Dynamo表实例:
import * as lambda from 'aws-cdk-lib/aws-lambda'; import { Construct } from 'constructs'; import { Table } from 'aws-cdk-lib/aws-dynamodb'; // 定义返回的Lambda集合类型,方便主Stack和其他模块引用 export interface ItemLambdas { getOne: lambda.Function; getAll: lambda.Function; } export function createItemLambdas(scope: Construct, itemsTable: Table): ItemLambdas { const getOneLambda = new lambda.Function(scope, "getOneItemFunction", { code: new lambda.AssetCode("src"), handler: "get-one.handler", runtime: lambda.Runtime.NODEJS_10_X, environment: { TABLE_NAME: itemsTable.tableName, PRIMARY_KEY: "itemId" } }); const getAllLambda = new lambda.Function(scope, "getAllItemsFunction", { code: new lambda.AssetCode("src"), handler: "get-all.handler", runtime: lambda.Runtime.NODEJS_10_X, environment: { TABLE_NAME: itemsTable.tableName, PRIMARY_KEY: "itemId" } }); // 把表的权限绑定逻辑也放在当前文件中,不需要放到主Stack itemsTable.grantReadWriteData(getAllLambda); itemsTable.grantReadWriteData(getOneLambda); return { getOne: getOneLambda, getAll: getAllLambda }; }
3. 拆分API网关配置到独立文件
新建src/resources/api-gateway.ts,集中管理API的创建、路由绑定逻辑,入参传入依赖的Lambda实例:
import * as apigateway from 'aws-cdk-lib/aws-apigateway'; import { Construct } from 'constructs'; import { ItemLambdas } from './lambdas'; export function createItemsApi(scope: Construct, itemLambdas: ItemLambdas) { const api = new apigateway.RestApi(scope, "itemsApi", { restApiName: "Items Service" }); const items = api.root.addResource("items"); const getAllIntegration = new apigateway.LambdaIntegration(itemLambdas.getAll); items.addMethod("GET", getAllIntegration); const singleItem = items.addResource("{id}"); const getOneIntegration = new apigateway.LambdaIntegration(itemLambdas.getOne); singleItem.addMethod("GET", getOneIntegration); }
拆分后的主Stack实现
原来臃肿的Stack类会变得非常清爽,只需要按照资源依赖顺序调用拆分好的函数即可:
import * as cdk from 'aws-cdk-lib'; import { createItemsDynamoTable } from './resources/dynamo-table'; import { createItemLambdas } from './resources/lambdas'; import { createItemsApi } from './resources/api-gateway'; export class ApiLambdaCrudDynamoDBStack extends cdk.Stack { constructor(app: cdk.App, id: string) { super(app, id); const dynamoTable = createItemsDynamoTable(this); const itemLambdas = createItemLambdas(this, dynamoTable); createItemsApi(this, itemLambdas); } }
注意事项
- 所有拆分函数传入的scope都是主Stack的
this,生成的资源挂载层级和直接在Stack内定义完全一致,最终输出的CloudFormation模板不会有任何差异。 - 这种方式不需要引入任何自定义Construct类的额外复杂度,仅靠普通函数就能完成逻辑拆分,后续如果某个模块的逻辑复杂度提升,需要升级为自定义Construct类时,替换对应文件的实现即可,主Stack的调用代码不需要改动。
- 跨文件引用资源时,直接通过函数返回值传递即可,不需要把实例挂在Stack的公开属性上,减少不必要的公开接口暴露。
内容的提问来源于stack exchange,提问作者user7280963
相关产品推荐
相关产品推荐

