aws / aws-appsync-community

The AWS AppSync community
https://aws.amazon.com/appsync
Apache License 2.0
506 stars 32 forks source link

Runtime Error with transactWriteItems in AppSync JS Runtime on DynamoDB Versioned Data Source #340

Open asta331 opened 8 months ago

asta331 commented 8 months ago

I am experiencing a runtime error when using the transactWriteItems operation in the AppSync JavaScript runtime, specifically with a DynamoDB data source that has the versioning feature enabled. The same code operates correctly on a data source where versioning is not enabled.

Interestingly, the transactGetItems operation functions as expected in both environments. This makes sense as the GetItem operation is not affected by the versioning feature.

I have not found any documentation stating that the transactWriteItems operation is incompatible with versioned DynamoDB data sources. Therefore, I am reporting this issue for further investigation.

Steps to Reproduce

  1. example appsync schema:
    
    type Mutation {
    test(t: String): Boolean
    } 

schema { mutation: Mutation }


2. example resolver function:
```javascript
export function request(ctx) {
    const { t } = ctx.args;

    return {
        version: '2018-05-29',
        operation: 'TransactWriteItems',
        transactItems: [{
            table: 'test',
            operation: 'PutItem',
            key: util.dynamodb.toMapValues({ pk: "a", sk: "b"}),
            attributeValues: util.dynamodb.toMapValues({ hello: "world!", text: t }),
        }, {
            table: 'test',
            operation: 'PutItem',
            key: util.dynamodb.toMapValues({ pk: "a", sk: "c"}),
            attributeValues: util.dynamodb.toMapValues({ hello: "world!", text: t }),
        }],
    };
}

export function response(ctx) {
    console.log(ctx.result);
    return true;
}
  1. query

    mutation Test {
    test(t: "Hello")
    }
  2. error:

    {
    "data": {
    "test": null
    },
    "errors": [
    {
      "path": [
        "test"
      ],
      "data": null,
      "errorType": "Code",
      "errorInfo": null,
      "locations": [
        {
          "line": 64,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "Runtime Error"
    }
    ]
    }
travishaby commented 8 months ago

Also seeing this behavior with a TransactWriteItems call I'm attempting to make. One of the transaction items is a GetItem, but the other is a PutItem. Error I'm seeing has nothing helpful, just that it's a Runtime error:

[
  {
    "path": ["<myPath>"],
    "data":null,
    "errorType":"Code",
    "errorInfo":null,
    "locations": [{"line":3,"column":13,"sourceName":null}],
    "message":"Runtime Error"
  }
]

In my case however, ~I don't believe my Dynamo table has versioning enabled~ I confirmed that my DDB data source does not have versioning enabled. 🤔

danielmarzan commented 7 months ago

I had the same issue also. It turns out I was missing returnValuesOnConditionCheckFailure

This works for me:

import { AppSyncIdentityCognito, Context, DynamoDBTransactWriteItemsRequest, } from "@aws-appsync/utils";

export function request(ctx: Context) { const { username } = ctx.identity as AppSyncIdentityCognito; const { postId } = ctx.arguments; const transactionWriteItems: DynamoDBTransactWriteItemsRequest = { operation: "TransactWriteItems", transactItems: [ { table: "#likesTable#", operation: "PutItem", key: util.dynamodb.toMapValues({ userId: username, postId }), condition: { expression: "attribute_not_exists(postId)", returnValuesOnConditionCheckFailure: true, }, attributeValues: {}, }, { table: "#postsTable#", operation: "UpdateItem", key: util.dynamodb.toMapValues({ id: postId }), update: { expression: "ADD likes :one", expressionValues: { ":one": util.dynamodb.toDynamoDB(1), }, }, condition: { expression: "attribute_exists(id)", returnValuesOnConditionCheckFailure: true, }, }, { table: "#usersTable#", operation: "UpdateItem", key: util.dynamodb.toMapValues({ id: username }), update: { expression: "ADD likesCounts :one", expressionValues: { ":one": util.dynamodb.toDynamoDB(1), }, }, condition: { expression: "attribute_exists(id)", returnValuesOnConditionCheckFailure: true, }, }, ], };

return transactionWriteItems; }

export const response = (ctx: Context) => { if (ctx.error) { util.error(ctx.error.message, ctx.error.type); }

return true; };