How to create a local server for dialogflow chatbot? - javascript

I am trying to built a local server for dialogflow bot using a node.js framework but ,not able to establish one .
I am using serveo.net as tunneling as ngrok doesn't work as it is blocked by my institute.
I am able to launch a server but unable to get a response from it back to the dialogflow agent.
'use strict';
const {WebhookClient} = require('dialogflow-fulfillment');
const express = require("express"); //express
const bodyParser = require("body-parser"); //body-parser
const app = express(); //app
app.use(bodyParser.json);
app.use(bodyParser.urlencoded({
extended: true
})
);
const WEBHOOK = 'webhook';
app.get('/', (req, res) => res.send('online'));
app.post('/webhook', express.json(), (request, respond) => {
const agent = new WebhookClient({
request,
response
});
function webhookprocessing(request, response) {
const agent = new WebhookClient(request, response);
const action = agent.intent;
if (action == WEBHOOK) {
agent.add("My name is karthik");
} else {
agent.add("karthik");
}
}
function welcome() {
agent.add('Welcome to my agent!')
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set("webhook", webhookprocessing);
agent.handleRequest(intentMap)
//const agentPath = agent.entitiesClient.projectAgentPath("master-bot-53dee");
//console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
//console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
//console.log("Server Hit");
});
app.listen(process.env.PORT || 5000);
edit1: I am getting a request from google dialogflow but my local server isn't sending a response.
edit2: The response payload shown received by dialogflow from my node is
{
"responseId":"efaf7898-74de-4727-bf2a-8eeb32ba570a-baaf0c1f",
"queryResult":{
"queryText":"1",
"parameters":{
"number":1
},
"allRequiredParamsPresent":true,
"fulfillmentMessages":[
{
"text":{
"text":[
""
]
}
}
],
"intent":{
"name":"projects/master-bot-53dee/agent/intents/15b96d92-4adb-4657-8b15-ebdf7df180b4",
"displayName":"webhook"
},
"intentDetectionConfidence":1,
"diagnosticInfo":{
"webhook_latency_ms":4991
},
"languageCode":"en"
},
"webhookStatus":{
"code":4,
"message":"Webhook call failed. Error: Request timeout."
}
}
and the request payload send by dialogflow is
{
"responseId":"efaf7898-74de-4727-bf2a-8eeb32ba570a-baaf0c1f",
"queryResult":{
"queryText":"1",
"parameters":{
"number":1
},
"allRequiredParamsPresent":true,
"fulfillmentMessages":[
{
"text":{
"text":[
""
]
}
}
],
"intent":{
"name":"projects/master-bot-53dee/agent/intents/15b96d92-4adb-4657-8b15-ebdf7df180b4",
"displayName":"webhook"
},
"intentDetectionConfidence":1,
"languageCode":"en"
},
"originalDetectIntentRequest":{
"payload":{
}
},
"session":"projects/master-bot-53dee/agent/sessions/d1205a66-9eda-d79c-7677-75eeb402e7e5"
}
The request sent by dialogflow reaches my public url created by my tunneling software but there isn't any response from the localhost .
This image is a screenshot of my console where I appear to be getting a post request but there isn't a response appearing on dialogflow.
I have used this url to refer webhook url https://excedo.serveo.net/.

app.post('/webhook', express.json(), (request, respond) => { // error name of the param doesn't match its usage
This line you are using respond as the parameter and passing and using response instead .Please change line to -
app.post('/webhook', express.json(), (request, response) => {

The webhook isn't being called at the /webhook path because the configuration in Dialogflow is telling it the webhook is at /. If you change this to https://excedo.serveo.net/webhook it will be routed correctly.

Related

Not able to get params from Node.js Server Request by Axios

I am trying to make a simple application which tries to send an SMS. I am using Axios to send a request to the server to send the SMS, and I am using Node.js for the server.
Below given is a snippet of the code of App.js sending the request to server, with parameter NUM which contains the number that twilio (SMS Service) has to send an SMS to
const sendSMSClinic = async () => {
console.log("CLINIC SMS SENDING FUNCTION ACCESSED");
try {
let res = await axios.get("http://localhost:3001/api/mail", {params: {
NUM: "971561490375"
}});
} catch(AxiosError) {
console.log(AxiosError)
}
}
Below given is the code of index.js which initiates the node.js server and tries to send an SMS
const express = require('express');
const app = express();
const port = process.env.PORT || 3001;
var cors = require('cors')
app.use(cors())
const accountSid = 'AC8ae163a17e6e3d2ce63e64a98bac68c4';
const authToken = '0a13cc33147e4ffb34682097fbf6c49d';
const client = require('twilio')(accountSid, authToken);
app.get('/api/mail/:NUM', async (req, res) => {
console.log(req.params.NUM);
client.messages
.create({
to: '+971561490375',
from: '+16188160866',
body: 'REASON FOR CALL: CLINIC EMERGENCY'
})
.then(message => console.log(message.sid))
.done();
})
app.get("/",(req,res)=>{
res.status(200).send("successful")
})
app.listen(port, () => {
console.log('Server is up and running on port ', port);
})
The problem is that I am getting the below errors
GET http://localhost:3001/api/mail?NUM=971561490375 404 (Not Found)
and
AxiosError {message: 'Request failed with status code 404', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
You should change your axios request to:
const num = "971561490375";
const res = await axios.get(`http://localhost:3001/api/mail/${num}`)
If you want to add multiple path parameters you can edit your end-point declaration to:
app.get('/api/mail/:NUM/:NUM2', (req, res) => {
console.log(req.params.NUM, req.params.NUM2);
...
}
And your axios request to:
const num = "971561490375";
const num2 = "971561490375";
const res = await axios.get(`http://localhost:3001/api/mail/${num}/${num2}`);

how to get cookie in react passed from express js api (MERN stack)

I have an api in express js that stores token in cookie on the client-side (react). The cookie is generated only when the user logins into the site. For example, when I test the login api with the postman, the cookie is generated as expected like this:
But when I log in with react.js then no cookie is found in the browser. Looks like the cookie was not passed to the front end as the screenshot demonstrates below:
As we got an alert message this means express api is working perfectly without any error!!
Here is my index.js file on express js that includes cookie-parser middleware as well
require("dotenv").config();
const port = process.env.PORT || 5050;
const express = require("express");
const app = express();
const cors = require("cors");
const authRouter = require("./routes/auth");
var cookieParser = require('cookie-parser')
connect_db();
app.use(express.json());
app.use(cookieParser())
app.use(cors());
app.use("/" , authRouter);
app.listen(port , () => {
console.log("Server is running!!");
})
Code for setting up the cookie from express api only controller
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt')
const login = async (req, res) => {
const { email, password } = req.body;
try {
const checkDetails = await User.findOne({ email });
if (checkDetails) {
const { password: hashedPassword, token, username } = checkDetails;
bcrypt.compare(password, hashedPassword, function (err, matched) {
if (matched) {
res.cookie("token", token, { expires: new Date(Date.now() + (5 * 60000)) , httpOnly: true }).json({ "message": "You logged in sucessfully!" });
} else {
res.status(500).json({ "message": "Wrong password" });
}
});
} else {
res.status(500).json({ "message": "Wrong email" });
}
} catch (error) {
console.log(error.message);
}
}
Here is the react.js code that I am using to fetch data from api without using a proxy in package.json file
if (errors.length === 0) {
const isLogin = await fetch("http://localhost:5000/api/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: {
"Content-Type": "application/json"
}
});
const res = await isLogin.json();
if(res) alert(res.message);
}
I want to get to know what is the reason behind this "getting cookie in postman but not in the browser". Do I need to use any react package?
The network tab screenshot might help you.
If I see in the network tab I get the same cookie, set among the other headers
To my understanding, fetch doesn't send requests with the cookies your browser has stored for that domain, and similarly, it doesn't store any cookies it receives in the response. This seems to be the expected behaviour of fetch.
To override this, try setting the credentials option when making the request, like so:
fetch(url, {
// ...
credentials: 'include'
})
or, alternatively:
fetch(url, {
// ...
credentials: 'same-origin'
})
You can read more about the differences between the two here.
I got my error resolved with two changings in my code
In front end just added credentials: 'include'
fetch(url, {
method : "POST"
body : body,
headers : headers,
credentials: 'include'
})
And in back end just replaced app.use(cors()); to
app.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag'] }))
That's it got resolved, Now I have cookies stored in my browser!!! Great. Thanks to this article:
https://www.anycodings.com/2022/01/react-app-express-server-set-cookie-not.html
during development i also faced same things, let me help you that how i solve it,
Firstly you use proxy in your react package.json, below private one:-
"private": true,
"proxy":"http://127.0.0.1:5000",
mention the same port on which your node server is running
Like:-
app.listen(5000,'127.0.0.1',()=>{
console.log('Server is Running');
});
above both must be on same , now react will run on port 3000 as usual but now we will create proxy to react So, react and node ports get connected on same with the help of proxy indirectly.
Now, when you will make GET or POST request from react then don't provide full URL, only provide the path on which you wants to get hit in backend and get response,
Example:-
React side on sending request, follow like this:-
const submitHandler=()=>{
axios.post('/api/loginuser',
{mobile:inputField.mobile,password:inputField.password})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.log(err);
})
}
Node side where it will hit:-
app.post('/api/loginuser', async(req,res)=>{
//Your Code Stuff Here
res.send()
}
on both side same link should hit, it is very important
it will 100%.
don't forget to mention
on node main main where server is listening

When using a fetch request in a Node JS server it receives the body as blank

I was working on a user login system in Node JS and was making a POST request to the server like this.
let data = {
username: "John Doe",
password: "123abc",
}
let options = {
method: 'POST',
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(data),
}
fetch('/verify-login', options).then(function(r) {
return r.text();
}).then(function(dat) {
if (dat == 'n') {
document.getElementById('login-fail').innerHTML = 'User name or password is incorrect!';
} else {
console.log('Login Success');
}
});
Server Side code:
const express = require('express');
const port = 80;
const bodyParser = require("body-parser");
const fs = require('fs');
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
const cors = require("cors");
app.use(cors());
app.post('/verify-login', async function(q, r) {
let dat = await q.body; //<-- Body is just {} not what the fetch request sent
//do account check stuff with dat
if (success) {
r.send('y');
} else {
r.send('n');
}
});
app.listen(port, function() {
console.log("Started application on port %d", port);
});
This issue is that on the server side when I receive the request, the body is returned with '{}'. Does anybody know why this is happening and how I can fix it?
There are various data types you can pass to fetch through the body option.
If you pass something it doesn't recognise, it converts it to a string and sends that.
Converting a plain object to a string doesn't give you anything useful.
let data = {
username: "John Doe",
password: "123abc",
}
console.log(`${data}`);
You said you were sending JSON (with the Content-Type header. So you need to actually send JSON.
const json = JSON.stringify(data);

Error: read ECONNRESET in request with Token in nodejs

I have a small API made in nodejs with express. A while ago I did not touch it and everything worked perfectly. Only now have I decided to implement JsonWebToken. In Postman, the login works fine, however, when trying to send the token as a header in a request I get an error. When i don't send the token in the request, response successfull (obviously since there is no token, the endpoint returns a 401 to me).
If I try to do it after authenticating (saving the token in an environment variable) and this time assigning it to the header, the following happens
If I send anything if it works, apparently it has to do with the length of the token.
I have tried it outside of postman, and the same thing happens, so the error does not seem to be from postman.
I don't know how to solve the problem, apparently nodejs does not handle the request by the length of the token.Is there a way to expand that?
The nodejs server entry point is:
// Enviroment process
require("dotenv").config();
// Body Parser
const bodyParser = require("body-parser");
const cors = require("cors");
// Express server
const app = require("express")();
app.use(cors());
// BodyParser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Routes middleware
app.use(require("./routes/index"));
// Run server
app.listen(process.env.PORT, () => {
console.log(`Escuchando en el puerto ${process.env.PORT}`);
});
Routes:
const express = require("express");
const { checkToken } = require("../middlewares/authentication");
const app = express();
/// Base Routes
app.get(
"/equipments",
[checkToken],
require("../controllers/equipment/get_all.controller")
);
module.exports = app;
The checkToken middleware:
const jwt = require("jsonwebtoken");
const checkToken = (req, res, next) => {
const token = req.get("token") || req.query.token;
jwt.verify(token, process.env.SEED, (err, decoded) => {
if (err) {
return res.status(401).json({
ok: false,
error: {
message: "Invalid Token",
},
});
}
req.user = decoded.user;
next();
});
};
module.exports = {
checkToken,
};
The .env variables:
// Node env (development | production)
NODE_ENV=development
// Server Port
PORT=3000
// Token Time Expiration
TOKEN_EXPIRES=48h
// Token Seed
SEED=exampleseed
UPDATE
When I send the token through the body of the request, the error does not occur, and everything works correctly (obviously changing the middleware so that it receives it by the body). The problem is when I send it by headers or a query parameter.
const checkToken = (req, res, next) => {
// const token = req.get("token") || req.query.token;
const token = req.body.token;
jwt.verify(token, process.env.SEED, (err, decoded) => {
if (err) {
return res.status(401).json({
ok: false,
error: {
message: "Invalid Token",
},
});
}
req.user = decoded.user;
next();
});
};
UPDATE AND SOLUTION:
After trying only those files, I realized that the error did not come from these. The problem was in the authentication. When creating the token I used the information of the logged in user, however, I had not realized that it had a base64 image field.
// ... after login, user object contains object information
let token = jwt.sign(
{
user: {
id: user.id,
name: user.name,
image: user.image.base64Url
},
},
process.env.SEED,
{ expiresIn: process.env.TOKEN_EXPIRES }
);
The length of the base64 image made the token extremely long. Then when making the request and sending a string token with many characters, the reading error occurrs (Error: read ECONNRESET).
The solution was to ignore the image field when creating the token.
Finally, before an error of the same type, check that a field that contains too much information is not being sent.

Node and DialogFlow Error: UnhandledPromiseRejectionWarning: TypeError: sessionClient.projectAgentSessionPath is not a function

I'm trying to connect from Nodejs to DialogFlow. I have completed all the steps to configure the user agent, the intent, etc. If I lunch with NODEMON the app, all its ok, but when I send a GET or POST request I get this error:
"UnhandledPromiseRejectionWarning: TypeError: sessionClient.projectAgentSessionPath" and more. But I think the most relevant mistake is this.
The code I used it's the same as the APi docs. I don't know why I get this error.
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const dialogflow = require('#google-cloud/dialogflow');
const uuid = require('uuid');
//const sendReq = require('./reqDialogFlow');
async function runSample(projectId = 'helpcenter-qwoj') {
// A unique identifier for the given session
const sessionId = uuid.v4();
// Create a new session
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = sessionClient.projectAgentSessionPath(projectId, sessionId);
console.log(sessionPath);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: 'hello',
// The language used by the client (en-US)
languageCode: 'it',
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
};
app.get('/', (req, res) => {
res.send({ "hello": "Daniele Asteggiante" })
});
app.post('/api/textAPIE', (req, res) => {
res.send({ "text": "CIAO" });
runSample();
});
app.use(bodyParser.json());
const PORT = process.env.PORT || 5000;
app.listen(PORT);
i had the same error.
i had installed
npm i dialogflow
instead of
npm install #google-cloud/dialogflow
I tried to change the Express Version version with an earlier version 4.17.0 instead 4.17.1.
Now it goes.
change "sessionClient.projectAgentSessionPath" -> "sessionClient.sessionPath"
Found this solution on github:https://github.com/googleapis/nodejs-dialogflow/issues/127

Categories