Front-End Web & Mobile
Introducing new AWS AppSync module and functions for DynamoDB JavaScript resolvers
This article is written by Kim Wendt, Sr. Solutions Architect
AWS AppSync is a service that allows you to build, manage, and host GraphQL APIs in the cloud. With AppSync, you simply write your GraphQL schema and connect to data sources using resolvers. Resolvers are how AppSync translates GraphQL requests to retrieve information from the different data sources. In November 2022, AppSync introduced JavaScript resolvers to make it easier for developers to write their AppSync business logic. The launch of JavaScript resolvers included NPM libraries to simplify development: @aws-appsync/utils to provide type validation and autocompletion in code editors and @aws-appsync/eslint-plugin to catch and fix problems quickly during development.
Today, we’re making it even easier to write resolvers for Amazon DynamoDB with the launch of a new module and functions to interact with DynamoDB data sources. The new module simplify the code required to create DynamoDB requests for common operations like put
, get
, delete
, update
, scan
, sync
, and query
. In addition, the utility provides operation helpers to help you make granular changes to item attributes during updates. The module is available in the public @aws-appsync/utils
package along with type-definitions to allow developers to write type-safe code locally, when using TypeScript.
Overview
The new JavaScript module for DynamoDB data sources makes is easy to express DynamoDB requests with a few lines of code. For example, let’s say we want to add a new item to our DynamoDB table with a primaryKey
of id
and a set of key/value pairs for the attributes. The code below uses the ddb.put
utility which takes as input the key and item to construct a DynamoDB PutRequest
.
We can also retrieve information from our DyanamoDB data source using a scan
operation. For example, let’s say we’ve added a few more items to our table and now we want to retrieve a list of those items. The code below uses the ddb.scan
utility which takes as input limit
and nextToken
values to paginate the results returned from DynamoDB.
Now it’s your turn to use these functions with an AppSync API with additional resolver logic.
Getting started
You can get started with JavaScript module for DynamoDB in the AppSync console.
- In the AppSync console, choose Create API.
- For the API Type, leave all defaults selected then choose Next.
- On the Specify API details page, name your API ToDo-API then choose Next.
- On the Specify GraphQL resources page, choose Create type backed by a DynamoDB table now.
The AppSync console can assist you in creating a new GraphQL type, the operations associated with the type, and a DynamoDB table to serve as the data source. To illustrate the new JavaScript module functions, we will create a Todo
type with the following fields: id
, owner
, name
, severity
, and dueOn
.
- Fill in the Model information with the values below. To add a field, choose Add new field. For Model name, enter
ToDo
. In the Additional settings section, leave the Resolver runtime selected as AppSync JavaScript.
- In the Configure model table section, fill in the table name, primary key, and sort key with the values below, then choose Next.
- Confirm your API details and then choose Create API.
The ToDo-API, DynamoDB data source, and JavaScript resolvers are automatically created for you. From the Schema page, you can review and modify the GraphQL schema, edit resolvers, or attach new resolvers to the fields in your schema. Let’s update our resolver logic to use the new JavaScript module for DynamoDB.
- Navigate to the Schema page. In the Resolvers section, enter Mutation in the
Filter types...
search bar. - Choose the ToDoTable resolver for the
createToDo(...): ToDo
field.
The createToDo
resolver contains a helper function to construct a DynamoDB PutItem
request including a condition
, key
, and attributeValues
. These values are all converted to a map object which is how DynamoDB expects the PutItem
request.
function dynamodbPutRequest(params) {
const { key, values, condition: inCondObj } = params;
let condition;
if (inCondObj) {
condition = JSON.parse(util.transform.toDynamoDBConditionExpression(inCondObj));
if (condition && condition.expressionValues && !Object.keys(condition.expressionValues).length) {
delete condition.expressionValues;
}
}
return {
operation: 'PutItem',
key: util.dynamodb.toMapValues(key),
attributeValues: util.dynamodb.toMapValues(values),
condition,
}
}
Let’s simplify this logic using the JavaScript module for DynamoDB.
- Add the following import statement to the resolver code.
import { put } from '@aws-appsync/utils/dynamodb';
- Replace the request handler with the code below (and optionally delete the dynamodbPutRequest function), then choose Save.
Using the new module functions, we’re able to simplify the logic for constructing the condition operation, key, and attribute values. Now you no longer need to use the toMapValues
or toDynamoDBConditionExpression
utilities; this functionality is abstracted in the put
utility method.
Let’s take a look at a more complicated resolver for the updateToDo
operation.
- Navigate to the Schema page. In the Resolvers section, enter Mutation in the
Filter types...
search bar. - Choose the ToDoTable resolver for the
updateToDo(...): ToDo
field.
Similar to the createToDo
resolver, the updateToDo
resolver contains a helper function to construct a DynamoDB UpdateItem
request. Let’s simplify this logic using the new module.
- Add the following import statement to the resolver code.
- Replace the request handler with the code below, then choose Save.
Using the JavaScript module for DynamoDB, we’re able to simplify the code used to create the update expression by leveraging the operations
and update
functions. Here, to delete an attribute during the update, we check if a specified attribute is null and use operations.remove()
to mark it as being deleted.
The operations helpers provide functions that you can use to take different actions on your item attributes during an update. The available helpers are:
add()
: adds a new attribute, including complex structures with nested attributesremove()
: removes an attribute from the itemreplace()
: replaces an existing attribute (or nested attribute) during an updateincrement()
: increments an attribute by a given numberdecrement()
: decrements an attribute by a given numberappend()
: Add items to the end of an attribute listprepend()
: Add items to the start of an attribute listupdateListItem()
: Updates an item at specific index in the list
Using operations helpers, you can write complex update operations in a couple of lines in your JavaScript resolvers. For example:
The following update request will:
- increment the count attribute
- add “John” as a friend to the friends list
- add an address to the item
- and change the value of the 3rd list entry of the pet attribute.
The update is only be allowed if an item with the provided key (id
) exists and if the size of the friends list is less than 5.
You can find out more about the module functions in the AppSync documentation. For examples on how to use these new functions, please refer to the AWS AppSync examples repository.
Conclusion
In this post, we reviewed the new JavaScript module for DynamoDB to simplify resolver logic in AppSync resolvers. Additionally, we covered how to easily get started using AWS AppSync and how to write resolvers to use the new module. To learn more about JavaScript resolvers and the new functions for DynamoDB, see the documentation and the tutorials. You can also find easy-to-use samples and guides in the samples repository.