Code Movement

Using AWS Lambda to Read and Write to AWS DynamoDB

The following shows how to read and write to a DynamoDB table using AWS Lambda.

I have a composte heap in my backyard with a thermometer to measure the temperature. This blog goes over how to write to and read from a DynamoDB database in AWS. The data the lambda receives is the current temperature of the composte heap.

Writing to Dynamo DB

Two configured test events used with the lambda function.

// freezing-temp
{
  "temp": 32
}
// hot-temp
{
  "temp": 140
}
// WriteComposteHeapTemperature.js
const AWS = require('aws-sdk');

const ddb = new AWS.DynamoDB.DocumentClient({region: "us-west-2"});

exports.handler = async (event, context, callback) => {
    const requestId = context.awsRequestId;
    const temperature = event.temp
    
    await createHeapReport(requestId, event.temp).then(() => {
        callback(null, {
            statusCode: 201,
            body: '',
            headers: {
                'Access-Control-Allow-Origin' : '*'
            }
        }).catch((err) => {
            console.log(err)
        })
    });
};

function createHeapReport(requestId, temp) {
    const params = {
        TableName: 'FarmHeap',
        Item: {
            "messageId": requestId,
            "temp": temp
        }
    }
    return ddb.put(params).promise();
}

Execution Results when triggering ‘hot-temp’ event

Test Event Name
hot-temp

Response
{
  "statusCode": 201,
  "body": "",
  "headers": {
    "Access-Control-Allow-Origin": "*"
  }
}

Function Logs
START RequestId: e1ff895b-65a0-4d87-839b-f8fddec82c93 Version: $LATEST
END RequestId: e1ff895b-65a0-4d87-839b-f8fddec82c93
REPORT RequestId: e1ff895b-65a0-4d87-839b-f8fddec82c93	Duration: 724.30 ms	Billed Duration: 725 ms	Memory Size: 128 MB	Max Memory Used: 88 MB	Init Duration: 494.19 ms

Request ID
e1ff895b-65a0-4d87-839b-f8fddec82c93

If the function fails to write to the database its execution role needs to be modified. On your Function Overview page, click the Configuration Tab, and click on the Role Name. Then you will want to modify the role so that it has the permissions required. For DynamoDB you can give a lambda function permission to run for all tables, or only a specific table. In this case, since this function is specific to a table, such as saving the temperature of the Composte Heap, then it should only have the ability to Write to the ‘FarmHeap’ DynamoDB table.

Since we are seeing a statusCode of 201 we know the insert into DynamoDB is working correctly.

Now lets read from the table.

ReadFarmHeapTemperature

The following reads 10 temperatures from the ‘FarmHeap’ table and logs the temperature.

const AWS = require('aws-sdk');

const ddb = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'});

exports.handler = async (event, context, callback) => {
    await readFarmHeap().then(data => {
        data.Items.forEach(function(item) {
            let temperature = item.temp
            console.log(temperature)
         });
    });
};

function readFarmHeap(requestId) {
    const params = {
        TableName: 'FarmHeap',
        Limit: 10
    };
    return ddb.scan(params).promise();
}

To configure the lambda to have the correct read access you will need to do the following.
On your Function Overview page, click the Configuration Tab, and click on the Role Name. Then you will want to modify the role so that it has the permissions required.

The policy you will need to add is “AmazonDynamoDBReadOnlyAccess”.

With that policy you should be able to read from the table. After triggering several test events from the WriteComposteHeapTemperature you can run the ReadFarmHeapTemperature and you should see something like the following.

Test Event Name
readDataFromHeap

Response
null

Function Logs
START RequestId: a230dd11-179f-4574-ac9f-047048337dcf Version: $LATEST
2021-09-01T14:30:13.498Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	140
2021-09-01T14:30:13.537Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	32
2021-09-01T14:30:13.537Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	140
2021-09-01T14:30:13.537Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	28
2021-09-01T14:30:13.537Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	140
2021-09-01T14:30:13.537Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	140
2021-09-01T14:30:13.537Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	140
2021-09-01T14:30:13.538Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	28
2021-09-01T14:30:13.538Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	28
2021-09-01T14:30:13.538Z	a230dd11-179f-4574-ac9f-047048337dcf	INFO	28
END RequestId: a230dd11-179f-4574-ac9f-047048337dcf
REPORT RequestId: a230dd11-179f-4574-ac9f-047048337dcf	Duration: 753.28 ms	Billed Duration: 754 ms	Memory Size: 128 MB	Max Memory Used: 89 MB	Init Duration: 414.85 ms

Request ID
a230dd11-179f-4574-ac9f-047048337dcf

The temperature of the composte heap has a different meaning. Personally I use a 16 inch thermometer, and to maximize the growth of the organisms in the composte that break down the organic matter into usable soil it is important to keep the Heap at specific temperatures for specific reasons. A high temperature such as 158 will likely kill weed seeds, and an even hotter temperature such as 170 may be too hot and kill the bacteria. There is a balance to be found, and for that reason we could use lambda to track the temperature readings, and connect a wifi enabled thermometer to send the data it receives.

So lets make a function that takes in our temperature and returns a description of the heap temperature.

For your Read Lambda function lets create a new file next to your index.js called ‘heap.js’. Hmm… I wonder how many people have created a file called ‘heap’ and referred to a composte heap, and not a heap.

That aside… here is our heap.js.

// heap.js
function heapHealth(temp) {
    if (temp < 80) { 
        return "nothing";
    } else if (80 <= temp && temp < 100) {
        return "warm";
    } else if (100 <= temp && temp < 130) {
        return "active";
    } else if (130 <= temp && temp < 160) {
        return "hot";
    } else {
        return "really hot! Maybe too hot?!";
    }
}

module.exports = { heapHealth };

Then call that from our original function.

const AWS = require('aws-sdk');

const ddb = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'});

const { heapHealth } = require('./heap')

exports.handler = async (event, context, callback) => {
    await readRecentHeap().then(data => {
        data.Items.forEach(function(item) {
            let temperature = item.temp;
            let heapDescription = heapHealth(temperature);
            
            console.log(temperature,heapDescription);
        });
    });
};

function readRecentHeap(requestId) {
    const params = {
        TableName: 'FarmHeap',
        Limit: 10
    };
    return ddb.scan(params).promise();
}

Deploy the changes, and run the test again.

Test Event Name
readDataFromHeap

Response
null

Function Logs
START RequestId: 2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f Version: $LATEST
2021-09-01T14:40:20.461Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	140 hot
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	32 nothing
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	140 hot
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	28 nothing
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	140 hot
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	140 hot
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	140 hot
2021-09-01T14:40:20.480Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	28 nothing
2021-09-01T14:40:20.481Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	28 nothing
2021-09-01T14:40:20.481Z	2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	INFO	28 nothing
END RequestId: 2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f
REPORT RequestId: 2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f	Duration: 462.14 ms	Billed Duration: 463 ms	Memory Size: 128 MB	Max Memory Used: 91 MB

Request ID
2b85f0f8-a9e3-4c2f-ad90-bda853a0b76f

You are now on your way to building a serverless application for monitoring your farm composte heap.

May the composte be nutrient rich, and may the harvest be bountiful.

Happy coding.