Utilizing resolver mapping templates to auto-generate IDs and AWSDate’s in AppSync

Overview
When I first started using AppSync to create a GraphQL backend, it all seemed way too good to be true. You define your types, and AppSync handles creating your GraphQL schema for you. Although this is great in theory, there is one major drawback that left me stooped for a long time. That being, “how the h@ll do I auto-generate IDs and dates?”.
When the schema is generated for you, it makes some terrible assumptions about the Create<Table>Input
types that can lead to some very bad practices if you’re new to programming or just haven’t created a fully-scaled backend before. In this article, I’m going to walk you through how to auto-generate an ID and Date so you no longer have to worry about sending some garbage ID and Date that is generated on the client-side.
💻 Let’s get started!💻
Fixing AppSync generated GraphQL
Let’s assume you created a resource for your backend service that manages Posts
using AppSync. The following schema is an example of the GraphQL that be generated for you by AppSync:
type Post { id: ID! post_date: AWSDate! post_content: String! author_username: String! } input CreatePostInput { id: ID! post_date: AWSDate! post_content: String! author_username: String! } // .... more types
Before we can talk about how to generate ID’s, we need to clean the CreatePostInput
type that AppSync generated for us. The two changes that you will want to make are :
- Removing ID fields from the
Create
input types - Removing date created fields from
Create
input types
We want to do this is for two reasons: security and SWE consistency.
When we rely on the frontend apps to generate IDs / Dates for us, we have no idea where this information is really coming from and if it’s authentic. Could it be proxied? could the client be run through a debugger? As a result, most clients are very weak in terms of security, so we want to strip away these vital DB properties from create mutations
as these weaknesses can be used to a hackers’ advantage.
We also remove these to create consistency across applications. When you ask the client to generate the ID, you have no idea what they’re actually sending back as an ID. Could it be a number? Could it be a username? Who knows? Consequently, you have to create extra input validation on the backend as well as ask the frontend team to write the implementation on their end. The same thing goes for date-strings. The backend has to make the validation and all frontends have to write implementations 🤢.
KEY TAKEAWAY: just generate IDs/creation dates on the backend to increase the security and establish good SWE practices.
Now that we have removed id
and post_date
, your CreatePostInput
type will look something like this:
type Post { id: ID! post_date: AWSDate! content: String! } // updated to not accept an id or post_date input CreatePostInput { content: String! author_username: String! }
We can see that createPost
mutation will only accept the post content and username, but the Post
type still expects non-nil values for id
and post_date
. This means that it’s expected of us to generate the id
and post_date
variables so when posts are queried, their resolvers can return a valid Post
object.
Auto-generated ID and AWSDate
Now that we’ve fixed the CreatePostInput
type to not take in an ID and AWSDate, we need to generate these values before placing them in our DynamoDB table. If we don’t do this, then GraphQL will get mad at use nad throw an error when the Post
type is returned from the createPost
mutation. The reason GraphQL will throw an error is due to the fact that required id
and post_date
to not be null by using (!). Since we never assigned these values when creating our CreatePostInput
type, they’re both currently null in the DynamoDB because they’re not assigned as an attribute in the request mapping template.
What is a resolver mapping template (RMT)?
Per AWS docs, “[Resolver Mapping Templates] tell AWS AppSync how to translate an incoming GraphQL request into instructions for your backend data source, and how to translate the response from that data source back into a GraphQL response. They are written in Apache Velocity Template Language (VTL), which takes your request as input and outputs a JSON document containing the instructions for the resolver. You can use mapping templates for simple instructions, such as passing in arguments from GraphQL fields, or for more complex instructions, such as looping through arguments to build an item before inserting the item into DynamoDB.”.
In Layman’s terms, the resolver mapping template maps our GraphQL request to a type that the resolver can understand. Since the most common form of communication data is JSON, the resolver is returned the the GraphQL request structured as a JSON object.
Generating values in resolver mapping template
Now that we know what a resolver mapping template is, we need to add the functionality to auto-generate ID’s and dates. To do this, we need to go to the createPost
mutation and click on the Resolver
(PostTable) to the right of the mutation which can be seen below

Once you click on the resolver
, you will be taken to a resolver mapping template. Note that it will say request mapping template at the top (I believe that this is legacy from API gateway…) but it’s easiest to just think of it as the resolver mapping template for me so I don’t get confused. The mapping template will look something like this:

Notice that your template will look a little bit different than mine, but that’s completely fine! Likely in your code, the id will be retrieved from the context.args which contains the inputs from our createPost
endpoint. Since we did not include the id
a parameter to the function, we need to autogenerate the id
in our mapping template!
The main focus points that I want you to look at are in the key
property for the returned JSON object. You can see id
and post_date
are both assigned using a $util
function provided by AWS and not through the context. These are the two pieces of code that you will need to auto-generate your ID’s and Dates! 🍻
// Auto generate ID $util.dynamodb.toDynamoDBJson($util.autoId()) // Auto generate Date (add string to format to your liking) $util.dynamodb.toDynamoDBJson($util.time.nowFormatted("yyyy-MM-dd"))
In the code above, we’re simply saying “Utility functions, generate an ID, then the ID to DynamoDB JSON” and “Utility functions, generate a date using the current time and format it, then convert to DynamoDB JSON”. The reason we have to wrap the utility function result in the JSON converter is that our handler is expecting a JSON object. So, we need to make sure that what we pass to them is conforming to JSON standards! Pretty simple, huh? 👍🏽
Difference between key and attribute
I do want to bring one nuance in the example above to your attention. I have the post_date
as a sorting key for my posts and not as a normal document attribute. If you’re not sorting by post_date
(or enter some other sorting key/ secondary key), add the post_date
attribute where the default values are being added in the photo! The reason you would add the attribute it where the default values are and not in a key section, is because DynamoDB is not expecting a post_date
key and is expecting it to be a normal attribute.
Also, you can add the default values inside of the JSON object (just place it in without commas at the end). I personally prefer doing the mapping above the object, but it’s really up to you and how you want to structure the mapping object!
Wrap Up
As you can see, the resolver mapping template is very flexible and allows us to auto-generate values that we don’t want the user to have to pass in for security and SWE reasons. We also looked at some of the utility functions that AWS provides and how to use them to add default values/ auto-generated values to our mapped request.
Now that you have a basic understanding of RMT’s, try adding default values for various attributes in your collection(s). For instance, you might have an S3Metadata bucket, and you default the bucket name to some bucket that you have. The more practice you get with Apache Velocity and these template the better you will be with them!
Let me know if you have any tips or tricks with RMT’s and how you’re using them in your AppSync project down below! ⬇️
If you liked today’s content, make sure you subscribe to the newsletter down below and if you want to support my coffee addiction, help me out by buying me a coffee! It keeps me going to create more AWESOME FREE CONTENT FOR YOU! As always, thanks for taking the time to unwrap some bytes with me. Cheers! 🍻