简体   繁体   中英

Node.js do something after API call has returned

I'm making a call to the Amazon product API using aws-lib npm package. I'm trying to get the result of that call and then save that information into my database, the problem I keep running into is that if I make a call with lots of parameters when I try to set the result of the call to the product I get undefined because the API call hasn't been returned completely yet. I've attempted to use callbacks and promises to make sure the API result is completely returned before I do anything else but I can't get it to work.

This the the current state of my code

  var aws = require('aws-lib');
    var host = "http://webservices.amazon.co.uk/onca/xml"
    var prodAdvOptions = {
      host: "webservices.amazon.co.uk",
      region: "UK"
    };

// provide credentials 
var prodAdv = aws.createProdAdvClient(myKey, myPass, myId, prodAdvOptions);

.post(function(req, res) {

    // Options for the Amazon API
    var options = {
      ItemId: req.body.itemId,
      ResponseGroup: "OfferFull, ItemAttributes",
      Condition: "New",
      MerchantId: "Amazon"
    }
    getInfo(options, saveProduct, res);
}

  function getInfo(options, saveProduct, res){

    // Make call to the API
    prodAdv.call("ItemLookup", options, function(err, result) { 
       //create new product
       var product = new Product();
       product.name = result.name
       //assign lots more things to the product - these will return undefined which is the problem
       saveProduct(product);
    })
  };

function saveProduct(product){
  // save product to the database
};

This is the call to the API using aws-lib

exports.init = init;

function init(genericAWSClient) {
  return createProdAdvClient;

  function createProdAdvClient(accessKeyId, secretAccessKey, associateTag, options) {
    options = options || {};
    var client = genericAWSClient({
      host: options.host || "ecs.amazonaws.com",
      path: options.path || "/onca/xml",
      accessKeyId: accessKeyId,
      secretAccessKey: secretAccessKey,
      secure: options.secure
    });

    return {
      client: client,
      call: call
    };

    function call(action, query, callback) {
      query["Operation"] = action
      query["Service"] = "AWSECommerceService"
      query["Version"] = options.version || '2009-10-01'
      query["AssociateTag"] = associateTag;
      query["Region"] = options.region || "US"
      return client.call(action, query, callback);
    }
  }
}

I think I'm not using callbacks correctly or need another one for assigning the result to the product but can't work out where I'm going wrong.

Thanks for the help I've been banging my head against this for 2 days.

It might be easier to see what's going on initially without promises, then use promises after an understanding has been reached.

One option for the flow of the program is:

  1. POST request is made and post callback is called
  2. getInfo is called
  3. prodAdv is called which is ansynchronous, which means a callback will have to be provided with what to do after the call to aws has completed.
  4. in that callback saveProduct is called, another asynchronous function. saveProduct must register a callback so that you can perform some action when the call to the database has been completed.
  5. In that callback issue res.send

   api.post('somePost', function(req, resp) {
       makeAWSCallAsync(params, function(err, awsRespProducts) {
          saveProductsAsync(awsRespProducts, function(err, dbResp) {
              // db call has been completed 
              resp.send();        
          });        
       });        
    });

This is very bare bones, and along the way errors should probably be checked. Once this is working, you could refactor to use promises, which would remove the nested callbacks.

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