As of now, we can only create a single book or query for ALL of the books. Let's create a query that searches for a book by its ID.
It is very similar to querying for all of the books. You can copy over the code for the list books Lambda and then create a new handler function.
The function deviates since you need to search for a book by its ID. You will use the DynamoDB DocumentClient method, .put
instead of .list
. And you will pass that function an ID.
Tomasz Łakomy: [0:00] Currently, I'm only able to get all of the books. What if I wanted to get just a single book by its ID? Let's Implement that. First of all, we need to add another query to our graphql schema. I'm going to add a getBookById(). This is going to take a bookId as an argument, which is of type ID!, and is going to return a Book or null, if a book could not be located. Let me save that.
[0:23] Next, let's update our TypeScript types. To do that, open up the terminal, and I'm going to run npm run codegen. Let's take a look at our new types. Here, we can see the getBookById type, as well as QueryGetBookByIdArgs. We are going to use this type in our Lambda function.
[0:42] To create the Lambda function, let us go back to our stack. In terms of CDK stack, our getBookById function is going to be quite similar to the listBooks function. I'm going to just copy all of that, paste it over here, and let us just amend it. Instead of listBooks, I'm going to select all of that and change it to getBookById.
[1:04] To double-check, this is going to create a getBookById Lambda which is going to be implemented in a getBookById file. This is going to grant this function ReadData to DynamoDB. This is going to create a new data source for our AppSync API. This is going to make sure that whenever we query for getBookById, this Lambda function is going to be executed.
[1:25] Let's implement this function. I'm going to go to my functions and create a getBookById.ts file. Again, I'm going to start with an empty handler. Let me add the necessary imports. We need the AppSyncResolverHandler. Also, we need a type for a Book. Also, this QueryGetBookByIdArgs which we are going to use in just a second, as well as DynamoDB.
[1:47] Next up, let me create the documentClient. This is DynamoDB.DocumentClient. This has to be a new DynamoDB.DocumentClient. We need to specify the type for this handler function. It's going to be an AppSyncResolverHandler. Again, this is a generic type.
[2:03] The first argument of it are the arguments to this function. This is QueryGetBookByIdArgs. The second argument to this generic type is what is going to be returned from the function. It's going to be either a Book or null.
[2:15] In order to get a book by id, we need the id. I'm going to create a bookId which is going to be equal to event.arguments.bookId. Next, we need to fetch a book with this id from DynamoDB. That's going to be quite similar to other functions.
[2:31] If a BOOKS_TABLE is not specified, we want to return null. If something explodes, we want to also return null and just catch this error. Let me remove this null over here. Let us implement this behavior.
[2:41] In order to get an item from DynamoDB, I'm going to do await documentClient.get(). This function takes an object as argument. The first argument is TableName which is process.env.BOOKS_TABLE. The second argument is the Key. This Key is the partition key of this DynamoDB table.
[3:00] If you recall, in our stack over here where we defined the BOOKS_TABLE, we set the partitionKey to be the id of a given book. Here, I need to pass in the id which is equal to bookId. This needs to also return a promise.
[3:16] I would like to return something. This return value should be the actual book. I'm going to do const. I'm going to get the Item. This Item is actually our book. This type assertion is mandatory because TypeScript has no way of knowing what exactly am I getting from this DynamoDB table.
[3:32] Time to deploy and test our function. Let me run cdk deploy.
[3:37] Let's test our newly added query. Instead of using this GraphQL client, I'm going to do something else. I'm going to navigate to AppsSync Console in AWS Console and click on the name of my API. First, let me go to Schema. Here on the list of resolvers. I can scroll down a bit and see the resolvers for both listBooks and getBookById queries.
[3:57] In fact, speaking of queries, let me click on Queries tab over here. Let me close that. I can also use this in AppSync Console in order to test my queries. Let me delete all of that and click on getBookById. I need to specify a bookId. For instance, I'm going to specify "123" because I know I have a book like this in my DynamoDB.
[4:16] I'm going to also get the title, id, rating, and reviews. I'm going to send this query. Voila, we do get the "Atomic Habits." What happens if I try to find a book which doesn't exist in our DynamoDB table? I can hit Play. It's going to be null because we don't have a book with this particular id.