Now we have to set up our Lambda function to actually read data from our DynamoDB table.
The hard coded data in our handler function is getting deleted and being replaced with code that scans our table and returns its contents.
To make this happen we'll be using aws-sdk
to get access to DynamoDB.DocumentClient
which gives us a simple API for interacting with our tables.
Tomasz Łakomy: [0:00] Since we have created a DynamoDB table, it makes sense to fetch data from it, as opposed to hard-coding the data in our Lambda function. As such, I'm going to remove all of that, and we're going to implement this function again.
[0:13] In order to fetch data from DynamoDB in our Lambda function, we are going to need the AWS software development kit. In order to install it, run, npm install aws-sdk. I'm also going to install the types for AWS Lambda.
[0:27] With that installed, let us go back to our function. This function is supposed to return a list of all of those books. In order to do that, we're going to need to create a TypeScript type. I'm going to create a type, book, which is going to be, more or less, the representation of this, but in TypeScript.
[0:45] It's going to have an ID, which is a string. It's going to have a title, which is also a string. It's going to have a completed flag, which is optional, and it's a Boolean. It's going to have a rating, which is a number. It's going to have reviews, which is an array of string. A rating is also optional.
[1:02] We are going to need one more type. Currently, this handler is just an asynchronous Typescript function, whereas it is actually an AppSyncResolver. As such it should have a proper type. Let me import it. I'm going to do import from AWS Lambda. I'm going to get a type which is called AppSyncResolverHandler. This one.
[1:21] We're going to change the type of this handler to be of AppSyncResolverHandler. This is a generic type. The first argument to this generic type is whatever is the argument to this function. This function is not going to take any arguments. The second argument is the return value.
[1:37] This function can either return an array of books or it can return null. Currently, it is complaining because this function is not returning anything. Let's fix that. To start, we are going to read the data from a DynamoDB table, which may or may not succeed. As such, it is better to always wrap something like this in a try-catch.
[1:55] Whenever there's an error, I'm going to just console.error "Whoops" and just display this error. I'm going to return null. Next up, in order to read the data from DynamoDB, I'm going to import DynamoDB from AWS SDK.
[2:10] Next up, I'm going to create a new instance of documentClient, which is a new DynamoDB documentClient. A documentClient is essentially a simpler API for us to interact with DynamoDB API from our TypeScript code. With that, let us list all the books. I'm going to do cons data which is going to be equal await documentClient.
[2:32] I would like to use the scan operation in order to scan the entire table and get everything that is inside of it. A scan operation takes a TableName as an argument. This is a small problem. How do I know which table am I supposed to read from inside of this function?
[2:48] If you recall in our CDK stack, what we did is that we have passed an environment variable of BOOKS_TABLE to this function. Now is the time to use that. I'm going to do process.env.BOOKS_TABLE. In order to make the scan function to work with an await keyword, I have to return a promise.
[3:07] Now, I can return data.Items. I'm going to assign them as type of Book. TypeScript is complaining right now because the table name may or may not be specified. It has no way of knowing that this BOOKS_TABLE was passed into this function. I'm going to do something else.
[3:23] I'm going to add an if statement that if this BOOKS_TABLE is not defined, I'm going to log out an error, BOOKS_TABLE was not specified. I'm going to also return null. Right now, everything is fine. Typescript is not complaining.
[3:36] Two small things to notice. First of all, this is using a scan operation which is going to go for the entire DynamoDB table and return every single item that's inside of it. This can be costly for large tables. Currently, our table is very small so this is fine.
[3:51] Secondly, I had to use this type assertion over here. The reason for that is that TypeScript has no way of knowing that what we are going to store in this DynamoDB table are books. That is why we have to tell TypeScript first, "Hey, those items, this is going to be a list of books. This Book type is something that we have defined over here."
[4:10] Since our function is finished, now we can deploy it. I'm going to run CDK deploy in my terminal. OK. It was successfully deployed. As a reminder, in our DynamoDB table, we have two books. We have "A Philosophy of Software Design" and "Atomic Habits." Both of them, I highly recommend by the way.
[4:26] Let's test our newly implemented Lambda function. I'm going to paste in a GraphQL query which is supposed to list all the books with their IDs, title, rating, and so on. If I hit Play, we're going to see that our Lambda function has been successfully called. This Lambda function was able to bridge the data in DynamoDB table in order to fetch both of those books.