简体   繁体   中英

Read from DynamoDB with Lambda nodejs for Alexa Skill

Iam new to Skill and nodejs development and got my first problem very soon.

Basically, iam trying to read data from DynamoDB and let it speak over Alexa.

var title;

exports.handler = (event, context, callback) => { 
    getData();
    alexa = Alexa.handler(event, context, callback); 
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();     
};

const handlers = {
    'LaunchRequest': function () {
        this.emit('DoSomethingIntent');
    },
    'DoSomethingIntent': function () {      
        this.response.speak('Here are your data ' + title);
        this.emit(':responseReady');        
    },
};

function getData() {
    var ddb = new AWS.DynamoDB.DocumentClient({region:'eu-west-1'});
    var params = {
        TableName: 'data', 
        Key: {'data_id' : 1,},
    };      
    ddb.get(params, function(err, data) {
        if (err) {
        }else{
           title = data.Item.title;             
        }
    });
}

The problem is that the DynamoDB.DocumentClient.get function is running asynchron and at the same time when the DoSomethingIntent runs the title variable is undefined.

What would be the best practice to solve this problem?

The only Solution which has worked for me so far was that:

ddb.get(params, function(err, data) {
    if (err) {

    }else{
        title = data.Item.title;                                      
        alexa.registerHandlers(handlers);
        alexa.execute(); 
    }
});

But it does not seem very practical for me!

Your working solution is correct because if you write the execution logic then it will run before it completes Dynamodb callback. Please remember DynamoDB call is Asynchronous non-blocking I/O so it will not block any code to execute outside the callback. So better place to add Alexa execution logic is inside callback.

This is happening because ddb.get() function is asynchronous and callback is running after execution of your handler. So there is no certainty of variable title getting populated before your response is sent.

You can use native promise here.

Modify your getData function like below:

function getData() {
  var ddb = new AWS.DynamoDB.DocumentClient({region:'eu-west-1'});
  var params = {
      TableName: 'data', 
      Key: {'data_id' : 1,},
  };

  return new Promise((resolve,reject) => {
    ddb.get(params, function(err, data) {
        if (err) {
        }else{
          title = data.Item.title;
          resolve(title);       
        }
    });
  })
}

And do following changes in your handler function and response handler:

exports.handler = (event, context, callback) => { 
    // Remove getData() from here
    alexa = Alexa.handler(event, context, callback); 
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();     
};

const handlers = {
    'LaunchRequest': function () {
        this.emit('DoSomethingIntent');
    },
    'DoSomethingIntent': function () {
      getData()
      .then( (title) => {
        this.response.speak('Here are your data ' + title);
        this.emit(':responseReady'); 
      })
      .catch( (error) => { // Handler error gracefully
        console.log(error);
        this.response.speak('Something is wrong. Try later.')
        this.emit(':responseReady');
      })
    },
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM