0

I am trying to make an updateItem call to DynamoDB from an Express server hosted on a Lambda. I am trying to update a nested field in the "users" table called "general" that itself has the fields "gender" and "about". This is my PATCH request so far:


app.patch("/profile/general", async function (req, res) {
  
  let params; 

  let newGender; 
  let newAbout;

  if (req.body.general){
    if (req.body.general.gender){
      newGender =  req.body.general.gender
    }
    if (req.body.general.about){
      newAbout =  req.body.general.about
    }

    params = {
      TableName: "users",
      Key: {
        'id': { 'S': req.user.sub },
      },
      UpdateExpression: `set general.gender = ${newGender}, general.about = ${newAbout}`, 
      ReturnValues: "ALL_NEW",
    };
  }

  try {
    let newUserObj = await dynamodb.updateItem(params).promise(); 
    console.log("newUserObj: ", newUserObj); 
    res.json({ "newData": newUserObj });
  } catch (err){
    console.log("error: ", err); 
    res.json({ "error": err });
  }
});

With this setup, I get an error if there is the word "like" within the incoming req.body.general.about string. For example, if the knew incoming string for req.body.general.about is "I like cookies", then I get the error "ValidationException: Invalid UpdateExpression: Syntax error; token: "like"" in CloudWatch. So, is there a way to account for request keywords and make the lambda treat them as just part of the incoming String field? Of course, there are probably many similar keywords that would trigger a similar error.

Thanks

dl_atl
  • 49
  • 1
  • 6
  • You managed to get an "SQL injection" in DynamoDB... See https://stackoverflow.com/questions/41915438/node-js-aws-dynamodb-updateitem how to properly update an item. – luk2302 Aug 11 '23 at 12:27

1 Answers1

0

Use ExpressionAttributeNames and ExpressionAttributeValues always:

    params = {
      TableName: "users",
      Key: {
        'id': { 'S': req.user.sub },
      },
      UpdateExpression: `set #g.#gn = :ng, #g.#a = :na`, 
      ExpressionAttributeNames: {
         '#g': 'general', 
         '#gn': 'gender',
         '#a': 'about'
      },
      ExpressionAttributeValues: {
         ':ng': {'S': newGender}, 
         ':na': {'S': newAbout}, 
      },
      ReturnValues: "ALL_NEW",
    };
  }
Leeroy Hannigan
  • 11,409
  • 3
  • 14
  • 31
  • I would argue to use `ExpressionAttributeNames` as *in*frequently as possible, it makes the update entirely unreadable when trying to figure out what columns are being updated. – luk2302 Aug 11 '23 at 12:51
  • Your goes against best practices and not using ExpressionAttributeNames should be avoided as much as possible. – Leeroy Hannigan Aug 11 '23 at 14:52
  • If the best practices produces unreadable code then it is not a reasonable best practice. – luk2302 Aug 11 '23 at 14:57
  • Best practices are defined in line with the Well Architected Framework. The parameters serve a purpose, if you want to avoid conflicts with reserved key words then you should use them always. – Leeroy Hannigan Aug 11 '23 at 15:07