I am trying to get data from a function in a node module, that returns a json object, and show the json object in a router in my server.js file.
I am trying to export it like this:
// Export the function
exports.getTweets = function() {
var tweetResult = {};
twitter.get(
'/statuses/user_timeline.json',
{ screen_name: 'twitter', count: 5},
function (error, tweets) {
tweetResult = tweets;
}
);
return tweetResult;
};
And here is my server.js file, with the route that should return the json object
tweets = require("./twitter_stream.js"),
// set up the route for the json object
app.get("/tweets.json", function (req, res) {
console.log(tweets.getTweets());
});
I haven't been able to get anything but an empty object.
You need to pass a callback to the getTwitter function to receive the twitter result. The variable tweetResult is null when the code return tweetResult; is invoked.
Please check the code below to see how to use the callback in your code:
exports.getTweets = function(callback) {
twitter.get(
'/statuses/user_timeline.json',
{ screen_name: 'casperpschultz', count: 5},
function (error, tweets) {
//invoke the callback function passing the tweets
callback(tweets);
}
);
};
Code to invoke the getTweets function passing a callback function:
app.get("/tweets.json", function (req, res) {
//invoke getTweets passing a callback function by parameter
tweets.getTweets(function(tweets){
console.log(tweets);
});
});
Node.js works in an asynchronous way with callback, here is a good reference that explains it.
Related
I built a API gateway,Function compute and Tablestore(Nosql) using Alibaba cloud to receive http post data and insert it into the a Nosql database.
While testing my code, the insert function did not invoke before the callback response. I know I should use Async/Await, but just don't fully understand how to use it.
I've tried .promise() the insert function did invoke but the callback response of the http did not invoke.
How can I put the data into my database and also gets the callback of function handler?
Some of my code:
var TableStore=require('tablestore');
async function handler(event, context, callback) {
var putReq = {
tableName: 'wifi',
condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null),
primaryKey: [{ 'date':'123' }],
attributeColumns: [
{'col1': JSON.stringify(data)}, // string column
{'col2': 100}, // integer column
],
};
await client.putRow(putReq,function(err, data) {
if (err) return callback(err);
console.log('putRow suceess: %j', data);
callback(null, data);
});
const response = Object.assign(baseresponse, {
body: {
status: "ok",
body:event.body
}
});
callback(null, response);
}
module.exports.handler = handler;
My friend and I have been struggling with Node.js callbacks since yesterday. We have the following function:
// helperFunction.js
function foo(param) {
request.get({
url: <url>
headers: {<headers>}
}, (err, response, data) => {
array = []
obj.forEach(function (entry) {
// do stuff with array
};
});
return array;
});
}
module.exports.foobar = foo;
then we call that from our app.js.
Since yesterday, we have updated the code to wait for the callback by using a function, like so:
// app.js
//var bar = require('./helperFunction');
//console.log(helperFunction.foobar('param')); // prints undefined
function bar(){
console.log('Log something')
}
foo(bar);
but we don't know how to pass the parameter to foo. I tried to add param (which is a string) to bar but it doesn't work.
For the record, I'm aware of other posts such as this, but I cannot make it work on my code.
In foo you just add a callback parameter and instead of returning you call this function. As a convention, the first parameter of the callback function is the error object. If no error occurred, this object is null and the following parameters are the actual result of the function. Your code didn't include error handling so I added it. If error exists you won't receive any data and foo can't calculate whatever it tries to calculate. In this case, foo should either try to solve the problem itself or propagate the error to its caller.
function foo(param, cb) {
request.get({
url: <url>
headers: {<headers>}
}, (err, response, data) => {
if (err) {
return cb(err);
}
array = []
obj.forEach(function (entry) {
// do stuff with array
};
});
cb(null, array);
});
}
function bar(err, data){
console.log('Log something')
}
foo('some param', bar);
Pass a function to foo. Something like:
foo(() => bar("Hi, I'm something"));
function foo(fn, err) {
if (!err && fn instanceof Function) {
fn();
}
}
function bar(someThing){
console.log(`Log ${someThing}`);
}
I have this function in my code :
let request = require("request");
let getDrillDownData = function (userId, query, callback) {
query.id = userId;
let urlQuery = buildUrlFromQuery(query);
request.get({
url: urlQuery,
json: true
}, function (error, response, data) {
if (!error && response.statusCode === 200) {
return callback(null, calculateExtraData(data));
} else if (error) {
return callback(error, null);
}
});
};
and I wish to write some unit test which verify that when the function is called with correct parameters, it is running OK,
and if there is an error, it did return the error
I wrote this unit test code :
describe.only('Server Service Unit Test', function(){
var sinon = require('sinon'),
rewire = require('rewire');
var reportService;
var reportData = require('./reportData.json');
beforeEach(function(){
reportService = rewire('../../services/reports.server.service');
});
describe('report methods', function(){
var reportData;
var query = { id: "test"};
var userId = 'testuser';
var getDrillDownData;
var request;
beforeEach(function(){
getDrillDownData = reportService.__get__('getDrillDownData');
});
it ('should get drill down data by userId and query', function(done){
var getCallback = sinon.stub();
request = {
get: sinon.stub().withArgs({
url: query,
json: true
}, getCallback.withArgs("error", {statusCode: 200}, reportData))
};
reportService.__set__('request', request);
getDrillDownData(userId, query, function(err, returnData){
(err === null).should.eql(true);
//(getCallback.withArgs(undefined, {statusCode: 200}, reportData).calledOnce).equal(true);
done();
});
});
});
But I keep getting this error:
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
Can someone help?
Thanks
I would stub request.get() directly:
describe('report methods', function() {
// Make `request.get()` a Sinon stub.
beforeEach(function() {
sinon.stub(request, 'get');
});
// Restore the original function.
afterEach(function() {
request.get.restore();
});
it ('should get drill down data by userId and query', function(done) {
// See text.
request.get.yields(null, { statusCode : 200 }, { foo : 'bar' });
// Call your function.
getDrillDownData('userId', {}, function(err, data) {
...your test cases here...
done();
});
});
});
Using request.get.yields() (which calls the first function argument that Sinon can find in the argument list; in this case, it's the (error, response, data) callback that gets passed to request.get() in your function) you can tell Sinon which arguments to use to call the callback.
That way, you can check if the callback to request.get() handles all arguments properly.
You can use .withArgs() too (request.get.withArgs(...).yields(...)), although you have to be sure that you're using it correctly; otherwise, if the exact arguments don't match, Sinon will call the original request.get() instead of using the stubbed version.
Instead, I prefer using stub.calledWith() to check for the correct arguments after the call has been made. That integrates much better with Mocha as well, as you can use explicit assertions.
I have a function which is going to make a REST call, but it cannot do this until an auth token has been fetched.
So I wrapped the REST call in the 'then()' of the auth token call's promise, like so:
var RESTCall = function() {
return authTokenPromise.then(function() {
return $http.get('userService' {
userId: 1234,
someFlag: true
});
});
};
This has the result of waiting to fire off the call to the userService until the authToken promise (from the service that gets the auth token) has resolved.
The problem comes when I try to remove the hard-coded params that set userId and someFlag. What I want to do is this:
var RESTCall = function(params) {
return authTokenPromise.then(function() {
return $http.get('userService' {
userId: params.userId, // params is undefined
someFlag: params.flag // params is undefined
});
});
};
How do I pass params into the anonymous function scope created by then(function() {...})?
How to get the client method.call to wait for an asynchronous function to finish? Currently it reaches the end of the function and returns undefined.
Client.js
Meteor.call( 'openSession', sid, function( err, res ) {
// Return undefined undefined
console.log( err, res );
});
Server.js
Meteor.methods({
openSession: function( session_id ) {
util.post('OpenSession', {session: session_id, reset: false }, function( err, res ){
// return value here with callback?
session_key = res;
});
}
});
Recent versions of Meteor have provided the undocumented Meteor._wrapAsync function which turns a function with a standard (err, res) callback into a synchronous function, meaning that the current Fiber yields until the callback returns, and then uses Meteor.bindEnvironment to ensure that you retain the current Meteor environment variables (such as Meteor.userId()).
A simple use would be as the following:
asyncFunc = function(arg1, arg2, callback) {
// callback has the form function (err, res) {}
};
Meteor.methods({
"callFunc": function() {
syncFunc = Meteor._wrapAsync(asyncFunc);
res = syncFunc("foo", "bar"); // Errors will be thrown
}
});
You may also need to use function#bind to make sure that asyncFunc is called with the right context before wrapping it.
For more information see: https://www.eventedmind.com/tracks/feed-archive/meteor-meteor-wrapasync
I was able to find the answer in this gist. In order to run asynchronous code from within a method.call you use Futures which forces your function to wait.
var fut = new Future();
asyncfunc( data, function( err, res ){
fut.ret( res );
});
return fut.wait();
Update: Sorry, I should have read the question more carefully. It looks like this question was also asked and answered here.
Apart from futures, another pattern to consider might be updating another model with the data returned from the asynchronous call and then subscribing to that model's changes.
From the meteor.call documentation it looks like the the result argument (err, res) of your callback function should contain the output of your openSession function. But you aren't returning any values from your openSession function so the return value is undefined.
You can test this:
Client:
Meteor.call('foo', function(err, res) {
console.log(res); // undefined
});
Meteor.call('bar', function(err, res) {
console.log(res); // 'bar'
});
Server:
Meteor.methods({
foo: function() {
var foo = 'foo';
},
bar: function() {
var bar = 'bar';
return bar;
}
});