I made a messanager chatbot and tried to deploy it for the first time and after fighting with all kinds of errors I did connect my page, app and hooks.
Tough al seems working theres's no response from the bot. This is what i get in the error log.
I send "hi" and nothing back. When i google the response error that comes up, there's no solution that worked for me.
'use strict'
const
express=require('express'),
bodyParser = require('body-parser'),
app=express().use(bodyParser.json()); //creates http server
app.listen(process.env.PORT || 5000, () =>console.log('webhook is listening'));
app.post('/webhook', (req, res) => {
let body=req.body;
if(body.object === 'page'){
body.entry.forEach(function(entry){
//Gets the body of the webhook
let webhook_event=entry.messaging[0];
console.log(webhook_event);
//Gets the sender PSID
let sender_psid=webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
});
res.status(200).send('EVENT_RECEIVED');
}else{
res.sendStatus(404);
}
if(webhook_event.message){
handleMessage(sender_psid, webhook_event.message);
}else if(webhook_event.postback){
handlePostback(sender_psid, webhook_event.postback);
}
});
app.get('/', function (req, res) {
res.send('This is EngiBot Server');
});
app.get('/webhook', (req, res) => {
let VERIFY_TOKEN = "testbot_verify_token"
let mode= req.query['hub.mode'];
let token=req.query['hub.verify_token'];
let challange = req.query['hub.challange'];
if (req.query['hub.verify_token'] === VERIFY_TOKEN) {
res.send(req.query['hub.challenge']);
} else {
res.send('Invalid verify token');
}
if(mode && token){
if(mode==='subscribe' && token === VERIFY_TOKEN){
console.log('WEBHOOK_VERIFIED');
res.status(200).send(challange);
}else{
res.sendStatus(403);
}
}
});
function handleMessages(sender_psid, received_message){
let response;
if(received_message.text){
response = {
"text": 'You sent the message: "${received_message.text}". Now send an image!'
}
}else if(received_message.attachments){
let attachment_url=received_message.attachments[0].payload.url;
response = {
"attachment":{
"type": "template",
"payload":{
"template_type":"generic",
"elements": [{
"title": "Is this the right picture?",
"subtitle": "Tap a button to answer.",
"image_url": attachment_url,
"buttons": [
{
"type": "postback",
"title": "Yes!",
"payload":"yes",
},
{
"type": "postback",
"title": "No!",
"payload": "no",
}
],
}]
}
}
}
}
callSendAPI(sender.psid, response);
}
function handlePostback(sender_psid, received_postback){
let response;
let payload=received_postback.payload;
if(payload==='yes'){
response = {"text": "Thanks!"}
}else if (payload==="no"){
response ={"text": "Oops, try sending another image."}
}
callSendAPI(sender_psid, response);
}
function callSendAPI(sender_psid, response){
let request_body={
"recipient": {
"id": sender_psid
},
"message": response
}
request({
"uri":"",
"qs":{"access_token": PAGE_ACCESS_TOKEN},
"method": "POST",
"json": request_body
}, (err, res, body)=>{
if(!err){
console.log('message sent!')
}else {
console.error("Unable to send message:" + err);
}
});
}
There's a problem in the POST router. The 'webhook_event' is declared inside a foreach block inside a conditional block so its scope is internal to that block. To solve this you shall rewrite your code to match the scopes. This is the wrong router (i added some comments =
app.post('/webhook', (req, res) => {
let body=req.body;
// webhook_event == null -> true
if(body.object === 'page'){
body.entry.forEach(function(entry){
//Gets the body of the webhook
let webhook_event=entry.messaging[0]; // webhook_event declared // webhook_event == null -> false
console.log(webhook_event);
//Gets the sender PSID
let sender_psid=webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
});
res.status(200).send('EVENT_RECEIVED');
if(webhook_event.message){ // ReferenceError cause is not defined
handleMessage(sender_psid, webhook_event.message);
}else if(webhook_event.postback){ // ReferenceError cause is not defined
handlePostback(sender_psid, webhook_event.postback);
}
}else{
res.sendStatus(404);
}
});
Related
I am developing a REST API with AWS Lambda, API Gateway. Language is Node.js.
Please check the below code. There I am accepting a parameter called id then get data from the database and return back as the response.
const mysql = require('mysql2');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const con = mysql.createConnection({
host : prop.get('server.host'),
user : prop.get("server.username"),
password : prop.get("server.password"),
port : prop.get("server.port"),
database : prop.get("server.dbname")
});
exports.getMilestoneStatusByID = (event, context, callback) => {
const { id } = event.queryStringParameters;
console.log("id", id);
// allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = false;
const sql = "select * from milestone_status where idmilestone_status = ?";
con.execute(sql, [id], function (err, result) {
if (err) throw err;
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify(result),
"isBase64Encoded": false
};
callback(null, response)
});
};
However, in any case the id is null or no parameter provided, then the user gets the standard AWS error output, "message": "Internal server error". But what I need is to pass 404 status code, with the message Missing Parameters.
I tried to put the whole block inside the handler into a try-catch and tried to fire the following code inside the catch
var response = {
"statusCode": 404,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify("Missing Parameters"),
"isBase64Encoded": false
};
callback(null, response)
But non of these stopped me from getting the standard AWS error message, "message": "Internal server error".
How can I implement the error that I am looking for?
I am answering my own question. The issue was not with the returning of the error, but with the null check. This worked.
exports.getMilestoneStatusByID = (event, context, callback) => {
const params = event.queryStringParameters;
if (!params || params.id == null) {
var response = {
"statusCode": 404,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({ error: "Missing Parameters" }),
"isBase64Encoded": false
};
callback(null, response)
} else {
const { id } = params;
// ...
}
I am implementing a chatbot using nodejs and messages are not sending in order that's why I changed sendMessage() function and created promise but when I call sendMessage function using await keyword why this is making for loop very slow?
I also want to insert data into sql. Please help me
sendMessage Function
let sendMessage = (sender_psid, response) => {
return new Promise ((resolve,reject) => {
// Construct the message body
try{
let request_body = {
"recipient": {
"id": sender_psid
},
"message": {
"text": response
}
}
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v9.0/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
// console.log(body)
if (!err) {
resolve('Message Sent');
console.log('message sent!')
}
else {
reject("Unable to send Message "+err)
console.error("Unable to send message:" + err);
}
});
} catch (e){
reject (e);
}
});
};
handleMessage Function
let handleMessage = async(sender_psid, received_message) => {
for (let i = 0; i < selectedMembers.length; i++) {
let memberDetail = selectedMembers[i].split(",");
memberID = memberDetail[0];
memberName = memberDetail[1];
console.log(memberID);
// Query to insert values in Info table
query = "INSERT INTO info (task_id,task_desc,member_id,member_name,assigner_id,assigner_name) VALUES (?,?,?,?,?,?)";
values = [taskID, taskDescription, memberID, memberName, assignerID, assignerName];
// Query Execution
conn.query(query, values, function (err, result) {
if (err) throw err;
console.log("Member ID " + memberID + "Member Name " + memberName + "Inseted into info table");
});
await sendMessage(memberID, assignerName + " has assigned you a task.");
console.log(taskDescription);
await sendMessage(memberID, taskDescription);
}
sendMessage(assignerID, "Task Assigned Successfully to " + selectedMembers.length + " members.");
}
}
app.get('/api/notes/:id', (req, res, next) => {
fs.readFile(dataPath, 'utf-8', (err, data) => {
if (err) {
throw err;
}
const wholeData = JSON.parse(data);
const objects = wholeData.notes;
const inputId = parseInt(req.params.id);
if (inputId <= 0) {
res.status(400).json({error: 'id must be a postive integer'});
} else {
for (const key in objects) {
if (parseInt(objects[key].id) === inputId) {
res.status(200).json(objects[key])
} if (parseInt(objects[key].id) !== inputId) {
res.status(404).json({error: `bruh theres no id ${inputId}`})
}
}
}
})
})
this is my code so far i have assigned this in the global :
const dataPath = 'data.json';
and this is what the data.json file looks like
{
"nextId": 5,
"notes": {
"1": {
"id": 1,
"content": "The event loop is how a JavaScript runtime pushes asynchronous callbacks onto the stack once the stack is cleared."
},
"2": {
"id": 2,
"content": "Prototypal inheritance is how JavaScript objects delegate behavior."
},
"3": {
"id": 3,
"content": "In JavaScript, the value of `this` is determined when a function is called; not when it is defined."
},
"4": {
"id": 4,
"content": "A closure is formed when a function retains access to variables in its lexical scope."
}
}
}
if i type in the command line http -v get :3000/api/notes/3 , the error message statement executes when its suppose to execute the object with id 3
however when i delete the error message if statement. the code can retrieve object from the json file
how can i fix this?
The error you recieve
_http_outgoing.js:470 throw new ERR_HTTP_HEADERS_SENT('set'); ^ Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
is because you use res.json() inside a for...in loop. The first iteration will break the rest because it will send a response.
The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
you should manipulate data (object/array/collection) and then send it once outside the for...in loop.
something like this:
app.get('/api/notes/:id', (req, res, next) => {
fs.readFile(dataPath, 'utf-8', (err, data) => {
if (err) {
throw err;
}
const wholeData = JSON.parse(data);
const objects = wholeData.notes;
const inputId = parseInt(req.params.id);
if (inputId <= 0) {
res.status(400).json({error: 'id must be a postive integer'});
} else {
let obj= false;
for (const key in objects) {
if (parseInt(objects[key].id) === inputId) {
obj = objects[key];
}
}
if (obj) {
res.status(200).json(obj)
} else
res.status(404).json({error: `bruh theres no id ${inputId}`})
}
}
});
});
I am creating an application in which I want to use some data from a JSON, which is generated by another js file. Here is the code which is generating JSON
var request = require('request');
module.exports = {
foo:
request('https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c1d1e5d6-fe5c-42de-8713-60f272a3b63e?subscription-key=d3d3e4dfa8744be9b4ae47558df8fc5a&timezoneOffset=0&verbose=true&q=hey',function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log(body);
})
};
I am interested in body object, which is giving following contents -
{
"query": "hey",
"topScoringIntent": {
"intent": "Help",
"score": 0.500165462
},
"intents": [
{
"intent": "Help",
"score": 0.500165462
},
{
"intent": "None",
"score": 0.10364107
},
{
"intent": "SearchHotels",
"score": 0.00249445555
},
{
"intent": "ShowHotelsReviews",
"score": 9.451727E-06
}
],
"entities": []
}
Now I want to access value of intent from topScoringIntent element. That to in another JS file. I tried using body[1].intend but it gives undefined.
I am very new to javascript and need very basic code to do this. Please give some suggestions on this. Also plz tell me if this can be solved by body-parser and if yes then how?
Update - Here is the code where I want to use body['topScoringIntent'].intent as global.
require('dotenv-extended').load();
var builder = require('botbuilder');
var restify = require('restify');
var Store = require('./store');
var spellService = require('./spell-service');
var request = require('request');
var myJSON = require("JSON");
var fs = require('fs');
//var window = window;
var request = require("request");
var myJSON = require("JSON");
var globalVar = [];
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create connector and listen for messages
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
server.post('/api/messages', connector.listen());
function getMyBody(url, callback) {
request({
url: 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c1d1e5d6-fe5c-42de-8713-60f272a3b63e?subscription-key=d3d3e4dfa8744be9b4ae47558df8fc5a&timezoneOffset=0&verbose=true&q=hey',
json: true
}, function (error, response, body) {
if (error || response.statusCode !== 200) {
return callback(error || {statusCode: response.statusCode});
}
global.topScoringIntent = body['topScoringIntent'].intent;
//if(body['topScoringIntent'].intent == 'Help');
//console.log('yay');
callback(null, body);
});
}
getMyBody('https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c1d1e5d6-fe5c-42de-8713-60f272a3b63e?subscription-key=d3d3e4dfa8744be9b4ae47558df8fc5a&timezoneOffset=0&verbose=true&q=hey', function(err, body) {
if (err) {
console.log(err);
}
})
if(body['topScoringIntent'].intent == 'Help');
console.log('success');
This should work for you
console.log(response.topScoringIntent.intent);
body.topScoringIntent.intent will return 'Help'.
To use it globally you can set a var :
var body = {
"query": "hey",
"topScoringIntent": {
"intent": "Help",
"score": 0.500165462
},
"intents": [
{
"intent": "Help",
"score": 0.500165462
},
{
"intent": "None",
"score": 0.10364107
},
{
"intent": "SearchHotels",
"score": 0.00249445555
},
{
"intent": "ShowHotelsReviews",
"score": 9.451727E-06
}
],
"entities": []
}
var result = body.topScoringIntent.intent;
And then use result somewhere else :
console.log(result);
I am new to node and async...
I am getting an error saying I can't set headers after they sent when I am sending a response back to api-ai
Any idea why?
Below is the code for function - getUserFirstName(userId, name, callback):
var name = "";
function getUserFirstName(userId, name, callback) {
console.log('withParams function called');
request({
method: 'GET',
uri: "https://graph.facebook.com/v2.6/" + userId + "?fields=first_name,last_name,profile_pic,locale,timezone,gender&access_token=" + FB_PAGE_ACCESS_TOKEN
},
function (error, response) {
if (error) {
console.error('Error while userInfoRequest: ', error);
} else {
if(!typeof response.body != 'object'){
var body = JSON.parse(response.body);
name = body.first_name;
callback(null,name);
}else{
name = response.body.first_name;
callback(null,name);
}
}
});
}
Here is the code being executed:
app.post('/webhook/', (req, res) => {
var data = JSONbig.parse(req.body);
var action = data.result.action;
var facebook_message = [];
if(action == "input.welcome"){
var userId = data.originalRequest.data.sender.id;
async.series([
function(callback) {
getUserFirstName(userId, name, callback);
}
], function(err,results) {
if (results != undefined){ // results = "John"
facebook_message = [{
"text":"Heyyyoo. Welcome!"
}]
}else{
facebook_message = [{
"text":"Hey " + results +"! Welcome!" // Hey John! Welcome!
}]
}
res.json({ // line 308 - error here!
speech: "Greetings",
displayText: "Greetings",
"data": {
"facebook": facebook_message
},
source: "webhook"
});
});
}
// BUNCH OF LONG AND MESSY CODES OVER HERE...
return res.status(200).json({
status: "ok"
});
Error
Error: Cant set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (/app/node_modules/express/lib/response.js:719:10)
at ServerResponse.send (/app/mode_modules/express/lib/response.js:164:12)
at ServerRespose.json (/app/mode_modules/express/lib/response.js:250:15)
at /app/src/app.js: 308:15
at /app/node_modules/async/dist/async.js:3694:9
at /app/node_modules/async/dist/async.js:356:16
at replenish (/app/node_modules/async/dist/async.js:877.25)
at iterateeCallback (/app/node_modules/async/dist/async.js:867:17)
at /app/node_modules/async/dist/async.js:840:16
Remove the following:
return res.status(200).json({
status: "ok"
});