internal DynamoDbAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { //Stage setting for Deployment (Need to have Deploy = false in RestApiProps to configure the Stage string environment = "PRD"; //STORAGE INFRASTRUCTURE //Create a User DynamoDB Table with a GSI (Primary Key Table) var userDynamoDbTable = new Table(this, "User", new TableProps { TableName = environment + "-" + "User", PartitionKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "username", Type = AttributeType.STRING }, ReadCapacity = 1, WriteCapacity = 1, RemovalPolicy = RemovalPolicy.DESTROY }); //Adding the Global Secondary Index (GSI) userDynamoDbTable.AddGlobalSecondaryIndex(new GlobalSecondaryIndexProps { IndexName = "UserGSIEmailIndex", PartitionKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "email", Type = AttributeType.STRING }, ReadCapacity = 1, WriteCapacity = 1 }); //Create a City DynamoDB Table with an LSI (Composite Key Table) var cityDynamoDbTable = new Table(this, "City", new TableProps { TableName = environment + "-" + "City", PartitionKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "state", Type = AttributeType.STRING }, SortKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "city", Type = AttributeType.STRING }, ReadCapacity = 1, WriteCapacity = 1, RemovalPolicy = RemovalPolicy.DESTROY }); //Adding the Local Secondary Index (LSI) cityDynamoDbTable.AddLocalSecondaryIndex(new LocalSecondaryIndexProps { IndexName = "CityLSIPopulationIndex", SortKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "population", Type = AttributeType.NUMBER } }); //COMPUTE INFRASTRUCTURE //User Write DynamoDb Lambda var initializeTablesHandler = new Function(this, "initializeTablesHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, FunctionName = "initializeTablesHandler", Timeout = Duration.Seconds(20), //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::InitializeTablesLambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, ["USERTABLE"] = userDynamoDbTable.TableName, ["CITYTABLE"] = cityDynamoDbTable.TableName } }); userDynamoDbTable.GrantFullAccess(initializeTablesHandler); cityDynamoDbTable.GrantFullAccess(initializeTablesHandler); //TestPrimaryKeyTable Lambda var testPrimaryKeyTableLambdaHandler = new Function(this, "testPrimaryKeyTableLambdaHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, FunctionName = "testPrimaryKeyDynamoDB", Timeout = Duration.Seconds(20), //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::TestPrimaryKeyTableLambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, ["USERTABLE"] = userDynamoDbTable.TableName, ["CITYTABLE"] = cityDynamoDbTable.TableName } }); userDynamoDbTable.GrantFullAccess(testPrimaryKeyTableLambdaHandler); cityDynamoDbTable.GrantFullAccess(testPrimaryKeyTableLambdaHandler); //TestCompositeKeyTable Lambda var testCompositeKeyTableLambdaHandler = new Function(this, "testCompositeKeyTableLambdaHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, FunctionName = "testCompositeKeyDynamoDBLambda", Timeout = Duration.Seconds(20), //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::TestCompositeKeyTableLambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, ["USERTABLE"] = userDynamoDbTable.TableName, ["CITYTABLE"] = cityDynamoDbTable.TableName } }); userDynamoDbTable.GrantFullAccess(testCompositeKeyTableLambdaHandler); cityDynamoDbTable.GrantFullAccess(testCompositeKeyTableLambdaHandler); //This is the name of the API in the APIGateway var api = new RestApi(this, "DYNAMODBAPI", new RestApiProps { RestApiName = "dynamoDBAPI", Description = "This our DYNAMODBAPI", Deploy = false }); var deployment = new Deployment(this, "My Deployment", new DeploymentProps { Api = api }); var stage = new Amazon.CDK.AWS.APIGateway.Stage(this, "stage name", new Amazon.CDK.AWS.APIGateway.StageProps { Deployment = deployment, StageName = environment }); api.DeploymentStage = stage; //Lambda integrations var initializeTablesLambdaIntegration = new LambdaIntegration(initializeTablesHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); var testPrimaryKeyTableLambdaIntegration = new LambdaIntegration(testPrimaryKeyTableLambdaHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); var testCompositeKeyTableLambdaIntegration = new LambdaIntegration(testCompositeKeyTableLambdaHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); //It is up to you if you want to structure your lambdas in separate APIGateway APIs (RestApi) //Option 1: Adding at the top level of the APIGateway API // api.Root.AddMethod("POST", simpleLambdaIntegration); //Option 2: Or break out resources under one APIGateway API as follows var initializeTablesResource = api.Root.AddResource("initializetables"); var initializeTablesMethod = initializeTablesResource.AddMethod("POST", initializeTablesLambdaIntegration); var testPrimaryKeyDynamoDBResource = api.Root.AddResource("testprimarykeytable"); var testPrimaryKeyDynamoDBMethod = testPrimaryKeyDynamoDBResource.AddMethod("POST", testPrimaryKeyTableLambdaIntegration); var testCompositeKeyDBResource = api.Root.AddResource("testcompositekeytable"); var testCompositeKeyDynamoDBMethod = testCompositeKeyDBResource.AddMethod("POST", testCompositeKeyTableLambdaIntegration); //Output results of the CDK Deployment new CfnOutput(this, "A Region:", new CfnOutputProps() { Value = this.Region }); new CfnOutput(this, "B UserDynamoDBTable PrimaryKeyTable:", new CfnOutputProps() { Value = userDynamoDbTable.TableName }); new CfnOutput(this, "C CityDynamoDBTable CompositeKeyTable:", new CfnOutputProps() { Value = cityDynamoDbTable.TableName }); new CfnOutput(this, "D API Gateway API:", new CfnOutputProps() { Value = api.Url }); string urlPrefix = api.Url.Remove(api.Url.Length - 1); new CfnOutput(this, "E Initialize Tables Lambda:", new CfnOutputProps() { Value = urlPrefix + initializeTablesMethod.Resource.Path }); new CfnOutput(this, "F Test Primary Key DynamoDB Lambda:", new CfnOutputProps() { Value = urlPrefix + testPrimaryKeyDynamoDBMethod.Resource.Path }); new CfnOutput(this, "G Test Composite Key DynamoDB Lambda:", new CfnOutputProps() { Value = urlPrefix + testCompositeKeyDynamoDBMethod.Resource.Path }); }
internal CdkAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { //Stage setting for Deployment (Need to have Deploy = false in RestApiProps to configure the Stage string environment = "PRD"; //STORAGE INFRASTRUCTURE // default RemovalPolicy is RETAIN (on a "cdk destroy") //Create an S3 Bucket (s3 Buckets must be unique for each region) //S3 Buckets must be unique by region //NOTE: If you put objects in this S3 bucket you will be required to delete it manually var rand = new Random(); int randNumber = rand.Next(100000); var s3Bucket = new Bucket(this, "MyS3Bucket", new BucketProps { BucketName = (environment + "-MyS3Bucket" + randNumber).ToLower(), RemovalPolicy = RemovalPolicy.DESTROY }); //Create a DynamoDB Table var dynamoDbTable = new Table(this, "User", new TableProps { TableName = environment + "-" + "User", PartitionKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "email", Type = AttributeType.STRING }, ReadCapacity = 1, WriteCapacity = 1, RemovalPolicy = RemovalPolicy.DESTROY }); //COMPUTE INFRASTRUCTURE //Basic Lambda var simpleLambdaHandler = new Function(this, "simpleLambdaHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, FunctionName = "simpleLambda", //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::SimpleLambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, ["BUCKET"] = s3Bucket.BucketName } }); s3Bucket.GrantReadWrite(simpleLambdaHandler); //S3 Lambda var s3LambdaHandler = new Function(this, "s3LambdaHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Timeout = Duration.Seconds(20), FunctionName = "s3Lambda", //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::S3LambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, ["BUCKET"] = s3Bucket.BucketName, ["REGION"] = this.Region } }); s3Bucket.GrantReadWrite(s3LambdaHandler); //Write DynamoDb Lambda var writeDynamoDBHandler = new Function(this, "writeDynamoDBHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, FunctionName = "writeDynamoDB", Timeout = Duration.Seconds(20), //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::WriteDynamoDBLambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, //["BUCKET"] = s3Bucket.BucketName, ["TABLE"] = dynamoDbTable.TableName } }); dynamoDbTable.GrantFullAccess(writeDynamoDBHandler); //Read DynamoDb Lambda var readDynamoDBHandler = new Function(this, "readDynamoDBHandler", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, FunctionName = "readDynamoDBLambda", Timeout = Duration.Seconds(20), //Where to get the code Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"), Handler = "Lambdas::Lambdas.Function::ReadDynamoDBLambdaHandler", Environment = new Dictionary <string, string> { ["ENVIRONMENT"] = environment, ["BUCKET"] = s3Bucket.BucketName, ["TABLE"] = dynamoDbTable.TableName } }); dynamoDbTable.GrantFullAccess(readDynamoDBHandler); s3Bucket.GrantReadWrite(readDynamoDBHandler); //This is the name of the API in the APIGateway var api = new RestApi(this, "CDKAPI", new RestApiProps { RestApiName = "cdkAPI", Description = "This our CDKAPI", Deploy = false }); var deployment = new Deployment(this, "My Deployment", new DeploymentProps { Api = api }); var stage = new Amazon.CDK.AWS.APIGateway.Stage(this, "stage name", new Amazon.CDK.AWS.APIGateway.StageProps { Deployment = deployment, StageName = environment }); api.DeploymentStage = stage; //Lambda integrations var simpleLambdaIntegration = new LambdaIntegration(simpleLambdaHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); var s3LambdaIntegration = new LambdaIntegration(s3LambdaHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); var writeDynamoDbLambdaIntegration = new LambdaIntegration(writeDynamoDBHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); var readDynamoDbLambdaIntegration = new LambdaIntegration(readDynamoDBHandler, new LambdaIntegrationOptions { RequestTemplates = new Dictionary <string, string> { ["application/json"] = "{ \"statusCode\": \"200\" }" } }); //It is up to you if you want to structure your lambdas in separate APIGateway APIs (RestApi) //Option 1: Adding at the top level of the APIGateway API // api.Root.AddMethod("POST", simpleLambdaIntegration); //Option 2: Or break out resources under one APIGateway API as follows var simpleResource = api.Root.AddResource("simple"); var simpleMethod = simpleResource.AddMethod("POST", simpleLambdaIntegration); var s3Resource = api.Root.AddResource("s3"); var s3Method = s3Resource.AddMethod("POST", s3LambdaIntegration); var writeDynamoDBResource = api.Root.AddResource("writedynamodb"); var writeDynamoDBMethod = writeDynamoDBResource.AddMethod("POST", writeDynamoDbLambdaIntegration); var readDynamoDBResource = api.Root.AddResource("readdynamodb"); var readDynamoDBMethod = readDynamoDBResource.AddMethod("POST", readDynamoDbLambdaIntegration); //Output results of the CDK Deployment new CfnOutput(this, "A Region:", new CfnOutputProps() { Value = this.Region }); new CfnOutput(this, "B S3 Bucket:", new CfnOutputProps() { Value = s3Bucket.BucketName }); new CfnOutput(this, "C DynamoDBTable:", new CfnOutputProps() { Value = dynamoDbTable.TableName }); new CfnOutput(this, "D API Gateway API:", new CfnOutputProps() { Value = api.Url }); string urlPrefix = api.Url.Remove(api.Url.Length - 1); new CfnOutput(this, "E Simple Lambda:", new CfnOutputProps() { Value = urlPrefix + simpleMethod.Resource.Path }); new CfnOutput(this, "F S3 Lambda:", new CfnOutputProps() { Value = urlPrefix + s3Method.Resource.Path }); new CfnOutput(this, "G Write DynamoDB Lambda:", new CfnOutputProps() { Value = urlPrefix + writeDynamoDBMethod.Resource.Path }); new CfnOutput(this, "H Read DynamoDB Lambda:", new CfnOutputProps() { Value = urlPrefix + readDynamoDBMethod.Resource.Path }); }