7

I have been attempting to interact with AppSync/GraphQL from:

  • Lambda - Create (works) Update (does not change data)
  • Angular - Create/Update subscription received, but object is null
  • Angular - Spoof update (does not change data)
  • AppSync Console - Spoof update (does not change data)

Post:

mutation MyMutation {
  updateAsset(input: {
      id: "b34d3aa3-fbc4-48b5-acba-xxxxxxxxxxx",
      owner: "51b691a5-d088-4ac0-9f46-xxxxxxxxxxxx",
      description: "AppSync"
    }) {
    id
    owner
    description
  }
}

Response:

{
  "data": {
    "updateAsset": {
      "id": "b34d3aa3-fbc4-48b5-acba-xxxxxxxxxx",
      "owner": "51b691a5-d088-4ac0-9f46-xxxxxxxxxxx",
      "description": "Edit Edit from AppSync"
  }
}

The version in DynamoDB gets auto-incremented each time I send the query. But the description remains the same as originally set.

Auth Rules on Schema -

@auth(
    rules: [
        { allow: public, provider: apiKey, operations: [create, update, read] },
        { allow: private, provider: userPools, operations: [read, create, update, delete] }
        { allow: groups, groups: ["admin"], operations: [read, create, update, delete] }
    ])

For now on the Frontend I'm cheating and just requesting the data after I received a null subscription event. But as I've stated I only seem to be able to set any of the data once and then I can't update it.

Any insight appreciated.

Update: I even decided to try a DeleteAsset statement and it won't delete but revs the version.

I guess maybe the next sane thing to do is to either stand up a new environment or attempt to stand this up in a fresh account.

Update: I have a working theory this has something to do with Conflict detection / rejection. When I try to delete via AppSync direct I get a rejection. From Angular I just get the record back with no delete.

After adding additional Auth on the API, I remember it asked about conflict resolution and I chose "AutoMerge". Doc on this at https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html

Mark
  • 2,429
  • 20
  • 20

3 Answers3

13

After further review I'll note what happened in the hopes it helps someone else.

Created amplify add api This walked me thru a wizard. I used the existing Cognito UserPool since I had not foreseen I would need to call this API from a S3 Trigger (Lambda Function) later.

Now needing to grant apiKey or preferably IAM access from the Lambda to AppSync/GraphQL API I performed amplify update api and added the additional Auth setting. This asked me how I wanted to solve conflict, since more than one source can edit the data. Because I just hit "agree" on Terms and Conditions and rarely read the manual; I selected 'AutoMerge' .. sounds nice right?

So now if you read the fine print, edits made to a table will be rejected as we now have this _version (Int) that would need to get passed so AutoMerge can decide if it wants to take your change. It also creates an extra DataStore Table in DynamoDB tracking versions. So in order to properly deal with this strategy you'd need to extend your schema to include _version not just id or whatever primary key you opted to use.

Also note: if you delete it sets _delete Bool to true. This actually still is returned to the UI so now your initial query needs to filter off (or not) deleted records.

Determined I also didn't need this. I don't want to use a Datastore (least not now) so: I found the offender in transform.conf.json within the API. After executing amplify update api, GraphQL, I chose 'Disable Datastore for entire API` and it got rid of the ConflictHandler an ConflictDetection.

This was also agitating my Angular 11 subscription to Create/Update as the added values this created broke the expected model. Not to mention the even back due to nothing changing was null.

Mark
  • 2,429
  • 20
  • 20
5

Great information here, Mark. Thanks for the write up and updates.

I was playing around with this and with the Auto Merge conflict resolution strategy I was able to post an update using a GraphQL mutation by sending the current _version member along.

This function:

await API.graphql(
     graphqlOperation(updateAsset, { 
          input: { 
              id: assetToUpdate.id, 
              name: "Updated name", 
              _version: assetToUpdate._version 
          }
    }
));

Properly updates, contacts AppSync, and propagates the changes to DynamoDB/DataStore. Using the current version tells AppSync that we are up-to-date and able to edit the content. Then AppSync manages/increments the _version/_createdAt/etc.

Evan Simpson
  • 91
  • 1
  • 7
  • You bet, sometimes you feel like you're on a island. Appreciate everyone taking a similar journey. I'm having a lot of fun with Amplify. Just switched one of my main processing lambdas over to the arm64. Got the task done much faster over x86_64. – Mark Dec 08 '21 at 23:31
  • Found this just now after about 2 days of scratching my head. Thank you! NOWHERE did I find this in the documentation. – todbott Jun 14 '22 at 12:44
0

Adding _version to my mutation worked very well.

API.graphql({
    query: yourQuery,
    variables: {
        input: {
            id: 'your-id',
            ...
            _version: version,
        },
    },
});
Micah Katz
  • 140
  • 5