Completing Forrest Brazeal's Resume Challenge - Part 3
Published: 2023-04-24 03:07:54

Lambda and DynamoDB are fairly straight forward, but the web made me stumble again.

## Creating DynamoDB Tables in SAM

Using DynamoDB itself is pretty straight forward, it's just a database.

Getting the SAM template to configure the table was not too hard. there are two says to do it - a full blown DynamoDB table, and a serverless SimpleTable. I checked both ways out, but decided to go ahead and use the full blown DynamoDB table type.

In the process, I decided to go ahead and make another table to log the IP address of the callers. I thought that maybe I could use this table and just take a count of it to keep track of the visitor count.

But unfortunately, the table properties in DynamoDB don't update but every six hours. That's just way too long. The only other way is to do a full table scan, and that's even worse.

I settled on two tables - one for counts, and one for the logs. I implemented the count by giving just a type for the key, but also including a count in the attributes. The validation liked it, but deployment said I had to have the attributes and keys match.

I added the count to the key, but then in testing that was way worse. It would not read records without both type and current matching count. And to drop the count from the key forced CloudFormation to barf and say it could not modify keys on existing tables. It wanted me to rename them, but I decided just to delete the whole stack and deploy it again.

I also tried to use a float as the key for the log from the timestamp. Keys cant be floats, only decimals (as a numeric). So I flipped that one over to a string and had to delete and deploy again to fix that one.

## Getting Lambda to Talk with DynamoDB

The web search for example read and write code ended up biting me again. I was trying to use references that did not match what the current documentation was telling me. Everything was different, and nothing worked.

From the very first call of boto3, the examples I found were wrong. The examples said to declare a dynamodb client of boto3, but the official documentation said it should be a resource.

And all the get/put examples passed the TableName in as a named parameter, but the documentation did not mention that as a parameter at all. The docs wanted you to get a Table property from the DynamoDB resource first, then use that for all the get/put operations.

Once I stuck to the official docs, then things started working quickly.

But one thing the web search did help with, was being able to do update operations as one atomic transaction. The official docs were very confusing, but the info from the web made it clear enough how to define the parameters and expressions to have a single update automatically increment the count.

The documentation was helpful in figuring out how to get the resultant data back, so I didn't have to read the new record again.

## Roles to Access DynamoDB

One thing the web searches helped with was pointing out that the Lambda function would need to have policies to allow it to do certain operations with these two new DynamoDB tables. The Lambda function just gets an array of Policy attributes that will grand CRUD permissions on each of the two tables. The log table really only needs write permission, but I just went ahead and gave it full CRUD.

## Conclusion

It did take several hours, but I ended up getting the Lambda function logging the IP and timestamp (just for a primary key) of all requests and incrementing the count in a single operation.

Running a test from the deployed function or local invocations both perform the expected operations. There are not real functioning unit or integration tests yet, but that is coming soon.