AppSync: how to error on DynamoDB conditional check failures
Tags: appsync, aws, dynamodb, graphql
Published: 2020-04-18 00:03:46

---
title: AppSync: how to error on DynamoDB conditional check failures
published: true
date: 2020-04-15 18:56:46 UTC
tags: AppSync,AWS,DynamoDB,GraphQL
canonical_url: https://theburningmonk.com/2020/04/appsync-how-to-error-on-dynamodb-conditional-check-failures/
---

# TL;DR

To make an AppSync DynamoDB resolver throw exceptions on conditional check errors, we need to check `$context.error` in the response mapping template ourselves. Like this:

```
#if ( $ctx.error )
  #if ( $ctx.error.type.equals("DynamoDB:ConditionalCheckFailedException") )
    $util.error("your error message")
  #else
    $util.error($ctx.error.message, $ctx.error.type)
  #end
#end
$utils.toJson($context.result)
```

And now, the longer version.

# The problem

AppSync lets us perform DynamoDB operations (`GetItem`, `PutItem`, `UpdateItem` etc.) without having to write any custom Lambda functions.

For example, to perform `PutItem` against a DynamoDB table, we need a request template like this:

```
{
  "version" : "2018-05-29",
  "operation" : "PutItem",
  "key": {
    "name" : $utils.dynamodb.toDynamoDBJson($context.arguments.name)
  },
  "attributeValues" : {
    "imageUrl" : $utils.dynamodb.toDynamoDBJson(...),
    "displayName" : $utils.dynamodb.toDynamoDBJson(...)
  }
}
```

Often, we want to have separate `add` and `update` mutations rather than just a single `put` mutation. For instance, in a social network app I’m building for a client we have a pre-configured list of sports users can do together.

We want to track the no. of users who declare their interest in doing a sport with others. So we added a `count` attribute to each sport.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e975852ccb2a.png)

Every time a user updates his/her sports preference, we’ll process the change through the DynamoDB Stream from the `User` table. The `OnProfileUpdate` function calculates the deltas and updates the count attribute in the aforementioned `Sport` table.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e975861a8fb0.png)

Through our CMS, admins can add new sports or change the `displayName` and/or `imageUrl` to show for each sport. But we don’t want to override the `count` attribute, which is updated by this `OnProfileUpdate` function.

So we need two mutations:

- `addSport` : adds a new row to the `Sport` table using `PutItem`
- `updateSport` : updates an existing row in the `Sport` table using `UpdateItem` to update just the `displayName` and `imageUrl` attribtues.

In both cases, we need to use [condition expressions](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html#aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions) to ensure the sport doesn’t exist (for `addSport`) or it exists already (for `updateSport`). And we want to throw an appropriate error if the conditional check fails.

And that’s where the problem is?—?even when the conditional checks fail, the DynamoDB resolver did not return an error.

Given the following template for the `addSport` mutation:

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e97587670dd9.png)

The following `addSport` request should have resulted in an error, at least according to the [documented behaviour](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html). The `displayName` we tried to write was different from the existing data.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e97588627045.png)

Similarly, an `updateSport` mutation with a non-existent sport should have thrown an error. But instead, it simply returned `null`.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e97589834b04.png)

What’s going on here?

Since the [official examples](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html#aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions) are still referencing template version `2017–02–28 `(which is no longer supported), I suspect the behaviour has changed in template version `2018–05–29`.

For both `PutItem` and `UpdateItem`, when there is a conditional check error the resolver appears to fetch the current item and save it in the `$context.result`. This happens regardless if the item is different.

This is neither the behaviour I intuitively expect to see nor the behaviour that is current documented. I have raised this documentation issue through the Feedback channel on the documentation page. Hopefully, it’ll be addressed in the near future. In the meantime, if you run into this problem as I did then I hope this post helps you in some way.

# The solution

When the DynamoDB resolver catches a `ConditionalCheckFailedException`, it also stores the error in `$context.error`.

In the response mapping template, you can inspect this attribute yourself and either rethrow the error or throw a different error altogether.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e9758b02f67c.png)

With this simple change, I was able to get the desired behaviour for both `addSport` and `updateSport` mutations.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e9758c1e9e86.png)

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e9758ca74463.png)

This solution is based on the example from the [official changelog](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-changelog.html#aws-appsync-resolver-mapping-template-version-2018-05-29), but there’s a typo in the example there. I have reported this typo so hopefully, it’ll be fixed soon. I have verified the snippet I shared above, so use that for now.

![](https://theburningmonk.com/wp-content/uploads/2020/04/img_5e9758dd6e1ec.png)

I have had a lot of fun working with AppSync this past few weeks and I will share more of my experience with you soon. Watch this space.

Until next time!

 ![](https://theburningmonk.com/wp-content/uploads/2019/10/img_5dab0c477fc72.png)

Hi, my name is **Yan Cui**. I’m an **[AWS Serverless Hero](https://aws.amazon.com/developer/community/heroes/yan-cui/)** and the author of [**Production-Ready Serverless**](https://bit.ly/production-ready-serverless). I specialise in rapidly transitioning teams to serverless and building production-ready services on AWS.

Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.

You can contact me via [Email](mailto:theburningmonk.com), [Twitter](https://twitter.com/theburningmonk) and [LinkedIn](https://www.linkedin.com/in/theburningmonk/).

[Hire me.](https://theburningmonk.com/hire-me)

The post [AppSync: how to error on DynamoDB conditional check failures](https://theburningmonk.com/2020/04/appsync-how-to-error-on-dynamodb-conditional-check-failures/) appeared first on [theburningmonk.com](https://theburningmonk.com).

 ![](http://feeds.feedburner.com/~r/theburningmonk/~4/vHSE8BYKmwQ)