function sendError (req, res, error) {
var status = 200
status = getErrorCode(error) // For Eg the getErrorCode returns 500 val
// Send to client
res.sendStatus(status)
}
We have written above function in my node.js and jquery application and we have written below test case for the above function but its failing in mocha. Please help me out.
TEST CASE(Written in mocha)
if('send status to client', function(done) {
var req = {}
var res = {}
var error = {code:'ENODATA'}
sendError(req,res,error)
//Calling send error function via rewire method
assert.equal(res.status, 500)
done()
})
Error:
res.sendStatus is not a function
So my thinking is I am not passing proper response, so when it is trying to set sendstatus it is not able to. Somewhere I read the res should be the object of datatype of res(express module res) - I am not sure, if so how to give that res parameter?
Related
Hello friends, Help me out for coding dialogflow fulfillment.
here is the code where i'm invoking GET Api in inner request module and i want to api's output into outer function in conv.ask('Sales is 1 million metric tonnes ' + b)
Code:
var request = require('request');
var code1 = null;
const bodyParser = require('body-parser')
const { dialogflow } = require('actions-on-google');
const assistant = dialogflow({
clientId: "305xxxx407-rv9kocdxxxxxxxxxciouuq8f9ul2eg.apps.googleusercontent.com"
});
module.exports = (app) => {
const logger = console;
assistant.intent('Sales', (conv) => {
const baseurl = 'https://www.ixxxxxxt.in:3500/getunits?unitcode=4';
var a = request(baseurl, function(error, res, body) {
var Unit = JSON.parse(body);
if (!error && res.statusCode == 200) {
var code = JSON.stringify(Unit.description);
//res.render(test(Unit));
console.log(code); // Print the google web page.
}
})
var b = (a.code);
console.log(b);
conv.ask('Sales is 1 million metric tonnes ' + b);
})
You have a few issues here.
The first is understanding what request() is doing. You probably don't want what request() returns, but instead want access to the body, which you get from the function you define.
That function is actually the second parameter that you've passed to request(). It is referred to as the callback function, since when request() gets the data from the URL, it will call that function. So everything you want to do with body needs to be done inside the callback function.
However, since you're using the Dialogflow library, and this is being done inside an Intent Handler, you need to return a Promise to indicate that you're waiting for a result before it can reply to the user. While you can wrap request() in a Promise, there are better solutions, most notably using the request-promise-native package, which is very similar to the request package, but uses Promises.
This makes things a lot easier. Your code might look something more like this (untested):
var request = require('request-promise-native');
var code1 = null;
const { dialogflow } = require('actions-on-google');
const assistant = dialogflow({
clientId: "305xxxx407-rv9kocdxxxxxxxxxciouuq8f9ul2eg.apps.googleusercontent.com"
});
module.exports = (app) => {
const logger = console;
assistant.intent('Sales', (conv) => {
const baseurl = 'https://www.ixxxxxxt.in:3500/getunits?unitcode=4';
return request(baseurl)
.then( body => {
// You don't need the body parser anymore
let code = body.description;
conv.ask('Sales is 1 million metric tonnes ' + code);
})
.catch( err => {
console.error( err );
conv.ask('Something went wrong. What should I do now?');
});
})
I have a Hubot plugin, that listens for JIRA webhooks, and announces in a room when new tickets are created:
module.exports = (robot) ->
robot.router.post '/hubot/tickets', (req, res) ->
data = if req.body.payload? then JSON.parse req.body.payload else req.body
if data.webhookEvent = 'jira:issue_created'
console.dir("#{new Date()} New ticket created")
shortened_summary = if data.issue.fields.summary.length >= 20 then data.issue.fields.summary.substring(0, 20) + ' ...' else data.issue.fields.summary
shortened_description = if data.issue.fields.description.length >= 50 then data.issue.fields.description.substring(0, 50) + ' ...' else data.issue.fields.description
console.log("New **#{data.issue.fields.priority.name.split ' ', 1}** created by #{data.user.name} (**#{data.issue.fields.customfield_10030.name}**) - #{shortened_summary} - #{shortened_description}")
robot.messageRoom "glados-test", "New **#{data.issue.fields.priority.name.split ' ', 1}** | #{data.user.name} (**#{data.issue.fields.customfield_10030.name}**) | #{shortened_summary} | #{shortened_description}"
res.send 'OK'
I'd like to extend this, to perform lookup against a remote API - basically, there's extra info I want to lookup, then add into the message I'm passing to room.messageRoom. I'm using request, because I need digest support.
So the following snippet works fine on its own.
request = require('request')
company_lookup = request.get('https://example.com/clients/api/project?name=FOOBAR', (error, response, body) ->
contracts = JSON.parse(body)['contracts']
console.log contracts
).auth('johnsmith', 'johnspassword', false)
And this is where my JS/Node newbness comes out...lol.
I can process the response inside the callback - but I'm really sure how to access it outside of that callback?
And how should I be integrating this into the webhook processing code - do I just move the snippet inside the if block, and assign it to a variable?
I'd use a middleware (supposing you are using Express with Node.js) so you can add the company_lookup response to the req and use it into any route where you add the middleware. http://expressjs.com/guide/using-middleware.html
For example:
server.js
var middlewares = require('./middlewares');
module.exports = function (robot) {
// Tell the route to execute the middleware before continue
return robot.router.post(middlewares.company_loop, '/hubot/tickets', function (req, res) {
// Now in the req you have also the middleware response attached to req.contracts
console.log(req.contracts);
return res.send('OK');
});
};
middlewares.js
var request = require('request');
// This is your middleware where you can attach your response to the req
exports.company_lookup = function (req, res, next) {
request.get('https://example.com/clients/api/project?name=FOOBAR', function (error, response, body) {
var contracts;
contracts = JSON.parse(body)['contracts'];
// Add the response to req
req.contracts = contracts;
// Tell it to continue
next();
}).auth('johnsmith', 'johnspassword', false);
};
To optimize the response delay, it is necessary to perform work after are response has been sent back to the client. However, the only way I can seem to get code to run after the response is sent is by using setTimeout. Is there a better way? Perhaps somewhere to plug in code after the response is sent, or somewhere to run code asynchronously?
Here's some code.
koa = require 'koa'
router = require 'koa-router'
app = koa()
# routing
app.use router app
app
.get '/mypath', (next) ->
# ...
console.log 'Sending response'
yield next
# send response???
console.log 'Do some more work that the response shouldn\'t wait for'
Do NOT call ctx.res.end(), it is hacky and circumvents koa's response/middleware mechanism, which means you might aswell just use express.
Here is the proper solution, which I also posted to https://github.com/koajs/koa/issues/474#issuecomment-153394277
app.use(function *(next) {
// execute next middleware
yield next
// note that this promise is NOT yielded so it doesn't delay the response
// this means this middleware will return before the async operation is finished
// because of that, you also will not get a 500 if an error occurs, so better log it manually.
db.queryAsync('INSERT INTO bodies (?)', ['body']).catch(console.log)
})
app.use(function *() {
this.body = 'Hello World'
})
No need for ctx.end()
So in short, do
function *process(next) {
yield next;
processData(this.request.body);
}
NOT
function *process(next) {
yield next;
yield processData(this.request.body);
}
I have the same problem.
koa will end response only when all middleware finish(In application.js, respond is a response middleware, it end the response.)
app.callback = function(){
var mw = [respond].concat(this.middleware);
var gen = compose(mw);
var fn = co.wrap(gen);
var self = this;
if (!this.listeners('error').length) this.on('error', this.onerror);
return function(req, res){
res.statusCode = 404;
var ctx = self.createContext(req, res);
onFinished(res, ctx.onerror);
fn.call(ctx).catch(ctx.onerror);
}
};
But, we can make problem solved by calling response.end function which is node's api:
exports.endResponseEarly = function*(next){
var res = this.res;
var body = this.body;
if(res && body){
body = JSON.stringify(body);
this.length = Buffer.byteLength(body);
res.end(body);
}
yield* next;
};
you can run code in async task by use setTimeout, just like:
exports.invoke = function*() {
setTimeout(function(){
co(function*(){
yield doSomeTask();
});
},100);
this.body = 'ok';
};
In a server made with Express in Node.js, I have the following code for handling a GET request:
function articleReturner(celien) { // function querying a database (celien is a string, cetarticle is a JSON)
Article.findOne({ lien: celien}, function (err, cetarticle){
console.log(cetarticle); // it works
return cetarticle;
});
}
app.get('/selection/oui/', function(req, res) { // the URL requested ends with ?value=http://sweetrandoms.com, for example
var celien = req.param("value"); //
console.log(celien); // it works
articleReturner(celien); // calling the function defined above
res.render('selection_form.ejs', cetarticle); // doesn't work!
});
I know that data from the URL routing is correctly obtained by the server since the console correctly displays celien (a string). I also know that the function articleReturner(celien) is correctly querying the database because the console correctly displays cetarticle (a JSON).
But res.render('selection_form.ejs', cetarticle); is not working and the console displays ReferenceError: cetarticle is not defined... What am I missing? Thanks!
Function articleReturner is executed asynchronously and return cetarticle; doesn't make a lot of sense. You need to use callbacks or promises. Here is the code that uses callback to return result from articleReturner:
function articleReturner(celien, callback) {
Article.findOne({ lien: celien}, function (err, cetarticle){
console.log(cetarticle);
callback(err,cetarticle);
});
}
app.get('/selection/oui/', function(req, res) {
var celien = req.param("value"); //
console.log(celien); // it works
articleReturner(celien, function(err, cetarticle){
res.render('selection_form.ejs', cetarticle);
});
});
I spent a while trying to diagnose this error.
First I had created a subclass of EventEmitter
File Client.js
var bindToProcess = function(fct) {
if (fct && process.domain) {
return process.domain.bind(fct)
}
return fct
};
function Client(){
EventEmitter.call(this);
}
util.inherits(Client, EventEmitter);
Client.prototype.success =
function(fct) {
this.on('success', bindToProcess(fct))
return this;
}
Client.prototype.login = function(username, password) {
body = {
username : username,
password : password
};
var self = this;
request.post(url, { json:true, body: body }, function (error, response, body) {
if (error ||response.statusCode != HTTPStatus.OK ) {
return self.emit('error', error);
}
return self.emit('success', body);
});
return this;
}
module.exports = Client
Then in another file in my Express App
File user.js
var Client = require('../utils/client');
var client = new Client();
// GET '/login'
exports.login = function(req, res){
client.login(username, password).success( function(user) {
res.redirect('/');
}).error( function(error) {
res.redirect('login');
});
}
The thing is though on the second request, the server crashes with the error:
Error: Can't set headers after they are sent.
In the interim I've solved the problem by created the Client inside the middleware rather than having it a global variable. I'm just curious why this is happening ?
Thanks,
(hopefully there is enough information)
What happens here is the call of the event handling function from the first request during second request because the variable client is shared between the requests.
At first, the client is created in the global scope. Then two handlers are attached to its events and then the request is actually performed and corresponding handler is called.
On the second request, two more handlers are attached to the same object and then on either success or fail two handlers (from previous call and from the current) are notified.
So you need to move the client creation to the action method or change how the code responds on the events - I can suggest promises-like approach: pass two callbacks as parameters to one method; or just the standard callback approach: pass the error result as first argument of the callback.