Back to Blog
Lesson 18 of the AWS: AWS Core Services for Developers course
Cloud NativeJuly 25, 20264 min read

Project Integration: Saving App Data to DynamoDB with AWS CDK

Learn to integrate your backend with persistent storage. We'll update CDK permissions, modify Lambda code, and verify data persistence in DynamoDB.

AWSCDKDynamoDBLambdaServerlessInfrastructure as Code
Close-up of HTML code displayed on a MacBook Pro screen, showcasing modern web development.

Previously in this course, we covered the fundamentals of Project Setup: Initializing the Web App Backend with AWS CDK and established the necessary data models in DynamoDB Data Modeling for Developers: A NoSQL Guide. Now, it’s time to wire these pieces together.

In this lesson, we move from theoretical infrastructure to functional integration. By the end of this guide, your serverless backend will be capable of receiving data and committing it to a DynamoDB table, fulfilling the core storage requirements of our running project.

Updating the CDK Stack for DynamoDB Access

Infrastructure as Code (IaC) isn't just about defining resources; it's about defining the relationships between them. Even if your Lambda code is perfect, it will fail if the underlying IAM role lacks the dynamodb:PutItem permission.

In your CDK stack file, you likely already have your table defined. We now need to grant your Lambda function access to that specific table. Using the grantReadWriteData method provided by the CDK is the safest approach, as it adheres to the principle of least privilege by only granting access to the resources you specify.

TYPESCRIPT
// Inside your Stack definition
const myTable = new dynamodb.Table(this, CE9178">'MyTable', {
  partitionKey: { name: CE9178">'id', type: dynamodb.AttributeType.STRING },
});

const myLambda = new lambda.Function(this, CE9178">'MyFunction', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: CE9178">'index.handler',
  code: lambda.Code.fromAsset(CE9178">'lambda'),
  environment: {
    TABLE_NAME: myTable.tableName,
  },
});

// Granting access
myTable.grantReadWriteData(myLambda);

By passing the TABLE_NAME as an environment variable, we ensure our Lambda knows exactly which resource to target without hardcoding values.

Modifying the Lambda Function for Data Insertion

Vibrant and engaging code displayed on a computer screen, showcasing programming concepts.

With the permissions in place, we update our application code to interact with the database. We will use the AWS SDK v3 for Node.js, which is modular and efficient for serverless environments.

Navigate to your lambda/index.js file and implement the PutCommand.

JAVASCRIPT
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

exports.handler = async (event) => {
  const { id, data } = JSON.parse(event.body);

  const command = new PutCommand({
    TableName: process.env.TABLE_NAME,
    Item: {
      id: id,
      content: data,
      timestamp: new Date().toISOString(),
    },
  });

  try {
    await docClient.send(command);
    return { statusCode: 200, body: JSON.stringify({ message: "Success" }) };
  } catch (error) {
    console.error(error);
    return { statusCode: 500, body: JSON.stringify({ error: "Failed to save" }) };
  }
};

This code pattern—creating a client, defining a command, and executing it—is the standard for Connecting Lambda to DynamoDB: A Backend Logic Guide.

Hands-on Exercise: Verifying Persistence

Now that the code is updated, it’s time to verify the integration:

  1. Deploy your changes: Run cdk deploy in your terminal. This updates the IAM policy and uploads your new function code.
  2. Invoke the function: Use the AWS CLI to trigger your Lambda with a mock event:
    Bash
    aws lambda invoke --function-name YourFunctionName --payload '{"body": "{\"id\": \"1\", \"data\": \"Hello World\"}"}' response.json
  3. Inspect DynamoDB: Open the AWS Console, navigate to your DynamoDB table, and click "Explore table items." You should see the record containing your ID and data.

Common Pitfalls

Close-up of a rusty sewer manhole cover in a grassy Boston park.

  • Incorrect IAM Permissions: If you receive a ResourceNotFoundException or AccessDeniedException, double-check that you called grantReadWriteData in your CDK stack.
  • Environment Variable Mismatches: Ensure the key TABLE_NAME used in the CDK stack matches exactly what you read in your Lambda process.env.
  • Missing SDK Dependencies: Since we are using AWS SDK v3, ensure your lambda/package.json includes @aws-sdk/client-dynamodb and @aws-sdk/lib-dynamodb.

FAQ

Q: Can I use the AWS SDK v2? A: AWS Lambda now includes the AWS SDK v3 by default in the Node.js runtime. It's recommended to stick with v3 for smaller bundle sizes and better performance.

Q: What happens if the table name changes? A: By using the TABLE_NAME environment variable, the Lambda function dynamically looks up the table name during execution. If you rename your table in CDK, the environment variable is automatically updated upon the next deployment.

Recap

Wooden Scrabble tiles spelling 'RECAP' on a brown textured background. Text concept image.

Integration is the final step in making your architecture "real." By leveraging CDK's grant methods, we ensure secure, scoped communication between our compute and storage layers. We've updated our infrastructure, implemented the insertion logic, and confirmed that our data actually lands where it's supposed to.

Up next: We will expose this functionality to the outside world by building the routing layer in API Gateway Routing and Integration.

Similar Posts