Right now our database is read-only. Let's fix that!
In GraphQL you make changes to your database using what are called mutations. We can define a mutation in our schema and then create a new lambda function that handles writing to our DynamoDB table.
Tomasz Łakomy: [0:00] Our API is getting better. Right now, we can list all the books, but we would like to be able to add a book to this list. In order to mutate data with GraphQL, we need a mutation. I'm going to create a new type called Mutation. Inside of it, I'm going to create a createBook mutation.
[0:16] This mutation will take an argument, which is of type book-input, which we are going to create in just a second. This mutation is going to return a book, or null, in case when a book was not able to be created.
[0:28] Next, we have to create the book-input. GraphQL has a special type, input, that we are going to use for a mutation. I'm going to do, input book-input. Inside of it, I'm going to only use the ID and the title. The reason for that is that, a brand new book is not very likely to have any rating or any reviews. Those are not going to be necessary in order to create a book.
[0:51] Next, go back to our stack and let's create the Lambda function. This Lambda function is going to be called createBookLambda. It's going to be a new Lambda, that function. The first argument is this. The second argument is createBook handler, and I'm going to assign a bunch of props.
[1:09] This createBookLambda is going to be quite similar to the listBooksLambda. That is, it's going to use exactly the same runtime, it's going to have its code in the same folder, and so on. I'm going to just copy and paste that over here. Of course, I need to change the name of the handler to createBook, that handler.
[1:27] This function also needs to be able to access the books table. In this case, it needs to be able to write data to our DynamoDB table. We are going to grant read/write data access to this createBookLambda. Next, we have to make sure that this createBookLambda is going to be executed whenever we send a GraphQL mutation. Similar to what we did for the listBooks, I'm going to create a data source.
[1:52] To do that, createBook data source. It's going to be, api add data source. This is a Lambda data source, and I'm going to call it, createBookDataSource. I'm going to pass in this createBookLambda function, except we have to create a GraphQL resolver. To this data source, we're going to attach a resolver.
[2:12] We would like this function, this createBookLambda function, to be executed whenever we have a mutation, and the mutation, in particular, is the field name, createBook.
[2:23] To recap, whenever there's a createBook mutation executed, we would like it to call this createBookLambda function. This is why we have created this data source. With all of that in place, let us implement this createBookLambda function. I'm going to create a new file called createbook.ts. I'm going to start with a simpler handler that always returns a null.
[2:44] Let's take a look at the schema. We know that our GraphQL mutation is always going to take a book as its input. We have to use that over here. Every time we call a Lambda function, an event is being passed in. Currently, we can see that this event is of type any, which isn't exactly what we want when we are writing TypeScript. We need a better type.
[3:03] Luckily, we can generate it. To do that, open the terminal and run npm, run codegen. Now, we can inspect the auto-generated types. The most important one for us is the MutationCreateBookArgs. This is what we are going to use in our Lambda function.
[3:18] Let us import some types. I'm importing the AppSyncResolverHandler. Also, importing the type for Book and those arguments to a mutation. I'm going to change the type of this handler function to be of AppSyncResolverHander. Again, this is a generic type.
[3:32] The first argument are the arguments that are being passed into the function which in our case is the MutationCreateBooksArgs. The second argument to this generic type is what is going to be returned from the function. In our case, it's going to be either a Book or null.
[3:46] Now, if I hover over event, we can see that this is of type AppSyncResolverEvent, MutationCreateBooksArgs. Now, we can get in the book from this event. I can do book = eventarguments.book because TypeScript knows that I'm going to pass in a book as an argument to this function.
[4:03] Next, we have to save this book in DynamoDB. In order to do that, I'm going to import DynamoDB from AWS SDK. I'm going to also create a documentClient which is an instance of new DynamoDB.DocumentClient. To simplify things a bit, I'm going to paste in some boilerplate.
[4:20] This is very similar to the listBooks function that we implemented earlier, that the BOOKS_TABLE has to be specified and whenever something explodes, we need to return null. Here, we're going to use the await documentClient in order to put a book in DynamoDB. Put takes an object as an argument which needs to have two things.
[4:40] First of all, we need to specify the TableName, process.env.BOOKS_TABLE. Secondly, we need to pass in the Item. The Item in our particular case is going to be the book passed in as an argument. I'm going to do book. I'm going to also return this book. One more thing, because I realized that I need to also return a promise from the put action to make this await keyword work properly.
[5:05] With all of that in place, we are ready to test our function. To do that, first, let us deploy our entire stack. After a successful deployment, let us go back to our GraphQL Client. If I click on the Schema over here, we can see that our schema was updated with a Mutation and the BookInput.
[5:22] Right now, we can create a book. I'm going to do mutation CreateBook. Let me close that. This is going to create a book with an ID of, I don't know, 999, and a title of Test Book. I'm going to also get the ID and the title of freshly-created book.
[5:38] Let me send that request. Awesome. It seems that the book was created. I'm going to also add a query to listBooks, and I'm going to list all the books. I'm going to get their ID, title, and reviews. Let me send a request for listBooks. It seems that everything works fine, and our new book was added to the list.
[5:57] Notice, that it doesn't have any reviews. That is by design, because we did not pass in any reviews when we created this book.
Member comments are a way for members to communicate, interact, and ask questions about a lesson.
The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io
Be on-Topic
Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.
Avoid meta-discussion
Code Problems?
Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context
Details and Context
Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!