question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

update mutation with new cli does not work???

See original GitHub issue

Note: If your issue/bug is regarding the AWS Amplify Console service, please log it in the Amplify Console GitHub Issue Tracker

Describe the bug A clear and concise description of what the bug is. Create a new project with schema. I am unable to update any of the values with generated mutation graphql mutations with cli. I make sure the required input values are included in the inputs to update the non-required values when I run my mutations but no change. I have also tried the appsync console with no avail. I have erased and tried a whole new environment in the cli but the bug keeps repeating. I am using 4.16.1. I have Merge enabled. The backend schema has

_version: Int!
  _deleted: Boolean
  _lastChangedAt: AWSTimestamp!

included. I also have iam provider and cognito user pools for auth rules. I am trying to update Profile table for my webapp.

here the VTL template

## [Start] Determine request authentication mode **
#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) )
  #set( $authMode = "userPools" )
#end
## [End] Determine request authentication mode **
## [Start] Check authMode and execute owner/group checks **
#if( $authMode == "userPools" )
  ## [Start] Static Group Authorization Checks **
  #set($isStaticGroupAuthorized = $util.defaultIfNull(
            $isStaticGroupAuthorized, false))
  ## Authorization rule: { allow: groups, groups: ["Users"], groupClaim: "cognito:groups" } **
  #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []) )
  #set( $allowedGroups = ["Users"] )
  #foreach( $userGroup in $userGroups )
    #if( $allowedGroups.contains($userGroup) )
      #set( $isStaticGroupAuthorized = true )
      #break
    #end
  #end
  ## [End] Static Group Authorization Checks **


  #if( ! $isStaticGroupAuthorized )
    ## No dynamic group authorization rules **


    ## No owner authorization rules **


    ## [Start] Collect Auth Condition **
    #set( $authCondition = $util.defaultIfNull($authCondition, {
  "expression": "",
  "expressionNames": {},
  "expressionValues": {}
}) )
    #set( $totalAuthExpression = "" )
    ## Add dynamic group auth conditions if they exist **
    #if( $groupAuthExpressions )
      #foreach( $authExpr in $groupAuthExpressions )
        #set( $totalAuthExpression = "$totalAuthExpression $authExpr" )
        #if( $foreach.hasNext )
          #set( $totalAuthExpression = "$totalAuthExpression OR" )
        #end
      #end
    #end
    #if( $groupAuthExpressionNames )
      $util.qr($authCondition.expressionNames.putAll($groupAuthExpressionNames))
    #end
    #if( $groupAuthExpressionValues )
      $util.qr($authCondition.expressionValues.putAll($groupAuthExpressionValues))
    #end
    ## Add owner auth conditions if they exist **
    #if( $totalAuthExpression != "" && $ownerAuthExpressions && $ownerAuthExpressions.size() > 0 )
      #set( $totalAuthExpression = "$totalAuthExpression OR" )
    #end
    #if( $ownerAuthExpressions )
      #foreach( $authExpr in $ownerAuthExpressions )
        #set( $totalAuthExpression = "$totalAuthExpression $authExpr" )
        #if( $foreach.hasNext )
          #set( $totalAuthExpression = "$totalAuthExpression OR" )
        #end
      #end
    #end
    #if( $ownerAuthExpressionNames )
      $util.qr($authCondition.expressionNames.putAll($ownerAuthExpressionNames))
    #end
    #if( $ownerAuthExpressionValues )
      $util.qr($authCondition.expressionValues.putAll($ownerAuthExpressionValues))
    #end
    ## Set final expression if it has changed. **
    #if( $totalAuthExpression != "" )
      #if( $util.isNullOrEmpty($authCondition.expression) )
        #set( $authCondition.expression = "($totalAuthExpression)" )
      #else
        #set( $authCondition.expression = "$authCondition.expression AND ($totalAuthExpression)" )
      #end
    #end
    ## [End] Collect Auth Condition **
  #end


  ## [Start] Throw if unauthorized **
  #if( !($isStaticGroupAuthorized == true || ($totalAuthExpression != "")) )
    $util.unauthorized()
  #end
  ## [End] Throw if unauthorized **
#end
## [End] Check authMode and execute owner/group checks **

#if( $authCondition && $authCondition.expression != "" )
  #set( $condition = $authCondition )
  #if( $modelObjectKey )
    #foreach( $entry in $modelObjectKey.entrySet() )
      $util.qr($condition.put("expression", "$condition.expression AND attribute_exists(#keyCondition$velocityCount)"))
      $util.qr($condition.expressionNames.put("#keyCondition$velocityCount", "$entry.key"))
    #end
  #else
    $util.qr($condition.put("expression", "$condition.expression AND attribute_exists(#id)"))
    $util.qr($condition.expressionNames.put("#id", "id"))
  #end
#else
  #if( $modelObjectKey )
    #set( $condition = {
  "expression": "",
  "expressionNames": {},
  "expressionValues": {}
} )
    #foreach( $entry in $modelObjectKey.entrySet() )
      #if( $velocityCount == 1 )
        $util.qr($condition.put("expression", "attribute_exists(#keyCondition$velocityCount)"))
      #else
        $util.qr($condition.put("expression", "$condition.expression AND attribute_exists(#keyCondition$velocityCount)"))
      #end
      $util.qr($condition.expressionNames.put("#keyCondition$velocityCount", "$entry.key"))
    #end
  #else
    #set( $condition = {
  "expression": "attribute_exists(#id)",
  "expressionNames": {
      "#id": "id"
  },
  "expressionValues": {}
} )
  #end
#end
## Automatically set the updatedAt timestamp. **
$util.qr($context.args.input.put("updatedAt", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601())))
$util.qr($context.args.input.put("__typename", "Profile"))
## Update condition if type is @versioned **
#if( $versionedCondition )
  $util.qr($condition.put("expression", "($condition.expression) AND $versionedCondition.expression"))
  $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames))
  $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues))
#end
#if( $context.args.condition )
  #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) )
  $util.qr($condition.put("expression", "($condition.expression) AND $conditionFilterExpressions.expression"))
  $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames))
  $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues))
#end
#if( $condition.expressionValues && $condition.expressionValues.size() == 0 )
  #set( $condition = {
  "expression": $condition.expression,
  "expressionNames": $condition.expressionNames
} )
#end
#set( $expNames = {} )
#set( $expValues = {} )
#set( $expSet = {} )
#set( $expAdd = {} )
#set( $expRemove = [] )
#if( $modelObjectKey )
  #set( $keyFields = [] )
  #foreach( $entry in $modelObjectKey.entrySet() )
    $util.qr($keyFields.add("$entry.key"))
  #end
#else
  #set( $keyFields = ["id", "_version", "_deleted", "_lastChangedAt"] )
#end
#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() )
  #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey("$entry.key") )
    #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get("$entry.key") )
  #else
    #set( $entryKeyAttributeName = $entry.key )
  #end
  #if( $util.isNull($entry.value) )
    #set( $discard = $expRemove.add("#$entryKeyAttributeName") )
    $util.qr($expNames.put("#$entryKeyAttributeName", "$entry.key"))
  #else
    $util.qr($expSet.put("#$entryKeyAttributeName", ":$entryKeyAttributeName"))
    $util.qr($expNames.put("#$entryKeyAttributeName", "$entry.key"))
    $util.qr($expValues.put(":$entryKeyAttributeName", $util.dynamodb.toDynamoDB($entry.value)))
  #end
#end
#set( $expression = "" )
#if( !$expSet.isEmpty() )
  #set( $expression = "SET" )
  #foreach( $entry in $expSet.entrySet() )
    #set( $expression = "$expression $entry.key = $entry.value" )
    #if( $foreach.hasNext() )
      #set( $expression = "$expression," )
    #end
  #end
#end
#if( !$expAdd.isEmpty() )
  #set( $expression = "$expression ADD" )
  #foreach( $entry in $expAdd.entrySet() )
    #set( $expression = "$expression $entry.key $entry.value" )
    #if( $foreach.hasNext() )
      #set( $expression = "$expression," )
    #end
  #end
#end
#if( !$expRemove.isEmpty() )
  #set( $expression = "$expression REMOVE" )
  #foreach( $entry in $expRemove )
    #set( $expression = "$expression $entry" )
    #if( $foreach.hasNext() )
      #set( $expression = "$expression," )
    #end
  #end
#end
#set( $update = {} )
$util.qr($update.put("expression", "$expression"))
#if( !$expNames.isEmpty() )
  $util.qr($update.put("expressionNames", $expNames))
#end
#if( !$expValues.isEmpty() )
  $util.qr($update.put("expressionValues", $expValues))
#end
{
  "version": "2018-05-29",
  "operation": "UpdateItem",
  "key": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else {
  "id": {
      "S": $util.toJson($context.args.input.id)
  }
} #end,
  "update": $util.toJson($update),
  "condition": $util.toJson($condition),
  "_version": $util.defaultIfNull($ctx.args.input["_version"], "0")
}

here’s schema for table

type Profile
@model
@auth(rules: [
  { allow: public, provider: iam, operations: [read] },
  {allow: groups, groups: ["public"], operations: [read]},
  {allow: groups, groups: ["Users"]},
])
{
  id: ID!
  userId: ID!
  name: String!
  aboutMe: String
  profilePicture: String
  following: [UserHost] @connection(keyName: "byUser", fields: ["id"])
  followingCount: String
  user: User @connection(fields: ["userId"])
  stats: Stats @connection(fields: ["userId"])
}

here’s my react code:

const updateUserProfileForm = async (values) => {
    try {
      const {
        files,
        aboutMe,
      } = values;

      //  upload picture
      const filteredFiles = files.filter(file => file !== null);
      console.log(values, ' this is the values object');
      console.log(files, ' this is files');
      if (filteredFiles
        && filteredFiles[0]
        && filteredFiles[0].name) await uploadPicture(filteredFiles[0]);

      const params = (filteredFiles && filteredFiles[0] && filteredFiles[0].name)
        ? {
          input: {
            id: profileId,
            aboutMe,
            profilePicture: `${credId}/${profileId}/${escapeUnsafe(filteredFiles[0].name)}`,
            userId: userProfile.userId,
            name: userProfile.name,
          },
        }
        : {
          input: {
            id: profileId,
            aboutMe,
            userId: userProfile.userId,
            name: userProfile.name,
          },
        };

      const userProfileData = await API
        .graphql(
          graphqlOperation(
            UpdateUserProfile, params,
          ),
        );
      const { data: { updateProfile: newUserProfile } } = userProfileData;
      setUserProfile(newUserProfile);
      console.log(newUserProfile, ' this is NewUserProfile');
      setSuccess({
        header: 'Update successful!',
        content: 'Profile updated successfully.',
      });
      setError(null);
    } catch (e) {
      setSuccess(null);
      setError({
        header: 'Oops...something went wrong',
        content: 'Something went wrong with updating profile, please try again.',
      });
    }
  };

Amplify CLI Version You can use amplify -v to check the amplify cli version on your system 4.16.1 To Reproduce Steps to reproduce the behavior or terminal output if applicable

  1. create new schema
  2. create values inside dynamodb table using appsync
  3. use update mutation while including the required fields.

Expected behavior A clear and concise description of what you expected to happen. The values should update.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. Mac/Windows/Ubuntu]
  • Node Version. You can use node -v to check the node version on your system

v12.13.1

Additional context Add any other context about the problem here.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:24 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
RossWilliamscommented, Mar 21, 2020

tl;dr: When you call the “updateProfile” mutation, because you have versioning turned on, you need to pass in the current _version number as part of the update input object. In your react code I can see you aren’t doing this.

To test this and show it working properly:

  1. Create and push schema (I’ve removed references to Stats, UserHost, Customer)
$ yarn global add @aws-amplify/cli@4.16.1

$ amplify init
Enter a name for the project testMutation
? Enter a name for the environment one
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using none
? Source Directory Path:  src
? Distribution Directory Path: dist
? Build Command:  npm run-script build
? Start Command: npm run-script start
Using default provider  awscloudformation

$ amplify add auth
Using service: Cognito, provided by: awscloudformation
 
 The current configured provider is Amazon Cognito. 
 
 Do you want to use the default authentication and security configuration? Default configuration
 Warning: you will not be able to edit these selections. 
 How do you want users to be able to sign in? Username
 Do you want to configure advanced settings? No, I am done.

$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: testmutation
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Do you want to configure advanced settings for the GraphQL API Yes, I want to make some additional changes.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API IAM
? Configure conflict detection? Yes
? Select the default resolution strategy Auto Merge
? Do you have an annotated GraphQL schema? No
? Do you want a guided schema creation? No
? Provide a custom type name Profile

$ amplify push --yes
  1. In ./amplify/amplify-meta.json, note the values of UserPoolId and AppClientIDWeb
  2. create a user for testing
$ aws cognito-idp admin-create-user --user-pool-id ${UserPoolId} --username testing --temporary-password testing123 --user-attributes Name=email,Value="test@test.com"
$ aws cognito-idp create-group --user-pool-id ${UserPoolId} --group-name Users
$ aws cognito-idp admin-add-user-to-group --user-pool-id ${UserPoolId} --username testing2 --group Users
  1. navigate to AppSync in your region, https://eu-west-2.console.aws.amazon.com/appsync/ . Select queries on left hand side. Login, use AppClientIDWeb from step 2.

  2. execute the following mutations

mutation create {
  createProfile(input:{id: "456", userId:"testing2", name: "Ross"}) {
    id
    _version
  }
}

mutation update {
  updateProfile(input: {id:"456", profilePicture:"picture1", _version: 1}) {
    id
    profilePicture
    _version
  }
}

mutation update2 {
  updateProfile(input: {id:"456", profilePicture:"picture2", _version: 2}) {
    id
    profilePicture
  }
}
  1. Notice that profile picture starts undefined, is updated to “picture 1” and then is updated to “picture 2”
0reactions
github-actions[bot]commented, May 26, 2021

This issue has been automatically locked since there hasn’t been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels for those types of questions.

Read more comments on GitHub >

github_iconTop Results From Across the Web

AWS Graphql API mutation does not update DataStore
I'm able to create a new model, but not able to update it. From network tab I see that I send the new...
Read more >
API (GraphQL) - Create, update, delete data - JavaScript
In GraphQL, mutations are used to create, update, or delete data. Here are some examples of creating, updating, and deleting items using the...
Read more >
Mutations - Sanity.io
A patch mutation updates an existing document's contents. A patch will fail if the document does not exist. A patch mutation contains one...
Read more >
PostGraphile | CRUD Mutations
PostGraphile will automatically add CRUD mutations to the schema for each table; this behaviour can be disabled via the --disable-default-mutations CLI ...
Read more >
Updating data with mutations | Full-Stack Quickstart
Apply the useMutation hook · The first object in useMutation 's result tuple ( login ) is the mutate function we call to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found