I want to use user sessions in my Dialogflow bot currently whats happening is when I save something in a variable in webhook it saves for all the users I don't want it like that I want different sessions for unique users
const axios = require('axios');
const express = require('express')
const {WebhookClient} = require('dialogflow-fulfillment')
var cookieParser = require('cookie-parser');
var session = require('express-session');
const app = express()
app.use(express.json())
app.get('/', (req, res) => {
res.send("Server Is Working.....")
})
app.post('/webhook', (req, res) => {
// get agent from request
let agent = new WebhookClient({request: req, response: res})
// create intentMap for handle intent
let intentMap = new Map();
// add intent map 2nd parameter pass function
intentMap.set('weather',weatherIntent)
intentMap.set('sessiontest',sessiontest)
// now agent is handle request and pass intent map
agent.handleRequest(intentMap)
})
function sessiontest(agent){
agent.add("session")
}
function weatherIntent(agent){
const apiKey = "23756992e06787aa9225e9b361dfcd66"
const city = agent.parameters.city;
const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=imperial`
return axios.get(url)
.then(function (response) {
// handle success
console.log(response.data.main.temp);
agent.add("Temp in " + city + " is " + response.data.main.temp)
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always execut
});
}
app.listen(3000, () => {
console.log("Server is Running on port 3000")
})
You can store session data within the session itself, with the parameters being passed in the JSON request and response. You can use conv.data to provide a key-value pair of variables you want saved.
app.intent('Default Welcome Intent', conv => {
conv.data.someProperty = 'someValue'
})
Related
Right now I have a front end react application using axios and and a backend server using node.js and express. I cannot for the life of me get my serp api data to post so that my front end can get it through axios and display the json data. I know how to get data to the front end but I am not a backend developer so this is proving to be incredibly difficult at the moment. I'm able to get the data from the the external api, I just don't know how to post it once I get it. Also I would not like to have all these request running on server.js so I created a controller but I think that is where it is messing up. Any help is appreciated
//pictures controller
const SerpApi = require('google-search-results-nodejs');
const {json} = require("express");
const search = new SerpApi.GoogleSearch("674d023b72e91fcdf3da14c730387dcbdb611f548e094bfeab2fff5bd86493fe");
const handlePictures = async (req, res) => {
const params = {
q: "Coffee",
location: "Austin, Texas, United States",
hl: "en",
gl: "us",
google_domain: "google.com"
};
const callback = function(data) {
console.log(data);
return res.send(data);
};
// Show result as JSON
search.json(params, callback);
//res.end();
}
// the above code works. how do i then post it to the server so that i can retrieve it to the backend?
module.exports = {handlePictures};
//server.js
const express = require('express');
const app = express();
const path = require('path');
const cors = require('cors');
const corsOptions = require('./config/corsOptions');
const { logger } = require('./middleware/logEvents');
const errorHandler = require('./middleware/errorHandler');
const cookieParser = require('cookie-parser');
const credentials = require('./middleware/credentials');
const PORT = process.env.PORT || 3500;
// custom middleware logger
app.use(logger);
// Handle options credentials check - before CORS!
// and fetch cookies credentials requirement
app.use(credentials);
// Cross Origin Resource Sharing
app.use(cors(corsOptions));
// built-in middleware to handle urlencoded form data
app.use(express.urlencoded({ extended: false }));
// built-in middleware for json
app.use(express.json());
//middleware for cookies
app.use(cookieParser());
//serve static files
app.use('/', express.static(path.join(__dirname, '/public')));
// routes
app.use('/', require('./routes/root'));
app.use('/pictures', require('./routes/api/pictures'));
app.all('*', (req, res) => {
res.status(404);
if (req.accepts('html')) {
res.sendFile(path.join(__dirname, 'views', '404.html'));
} else if (req.accepts('json')) {
res.json({ "error": "404 Not Found" });
} else {
res.type('txt').send("404 Not Found");
}
});
app.use(errorHandler);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
//api/pictures.js
const picturesController= require('../../controllers/picturesController');
const express = require('express')
const router = express.Router();
// for POST request use app.post
router.route('/')
.post( async (req, res) => {
// use the controller to request external API
const response = await picturesController.handlePictures()
// send the response back to client
res.json(response)
})
module.exports = router;
You just need to return the result from SerpApi in your handlePictures function. To do this make a new Promise and when search.json runs callback do what you need with the results and pass it in resolve.
Your picturesController.js with an example of returning all results.
//pictures controller
const SerpApi = require("google-search-results-nodejs");
const { json } = require("express");
const search = new SerpApi.GoogleSearch(process.env.API_KEY); //your API key from serpapi.com
const handlePictures = async (req, res) => {
return new Promise((resolve) => {
const params = {
q: "Coffee",
location: "Austin, Texas, United States",
hl: "en",
gl: "us",
google_domain: "google.com",
};
const callback = function(data) {
resolve(data);
};
search.json(params, callback);
});
};
module.exports = { handlePictures };
Output:
And I advise you to change your API key to SerpApi to prevent it from being used by outsiders.
Since I don't have the full context of your App I can just assume the context. But given the fact that you already have wrapped the logic of calling the external API into a dedicated controller you can use it in the following way in an express app (used the hello world example from express):
// import your controller here
const express = require('express')
const app = express()
const port = 3000
// for POST request use app.post
app.get('/', async (req, res) => {
// use the controller to request external API
const response = await yourController.method()
// send the response back to client
res.json(response)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
Here's an example how to execute the http request from the frontend:
const response = await fetch('http://localhost:3000') // result from res.json(response)
I'm working on a Redis API and I can make GET requests from it so I know it works, but when I try making a POST request to http://localhost:3001/history/additem the terminal returns this error:
Error: node_redis: The HSET command contains a invalid argument type of "undefined". Only strings, dates and buffers are accepted. Please update your code to use valid argument types. OK
I can only assume its a problem with stringify
const express = require('express');
const app = express();
const connect = require('./Connection')
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const redis = require('redis')
const port = 3001
app.get('/', (req, res) => {
connect.createConnection().then(client => {
res.send('Search Bar Contents')
console.log(client);
})
});
app.post('/history/addItem', jsonParser, (req, res) => {
connect.createConnection().then(client => {
const history = JSON.stringify(req.body.history)
const uuid = req.body.uuid
client.hset(uuid, "history", history, redis.print)
client.hgetall(uuid, (err, results) => {
if(results){
res.send(results)
}else{
res.send(err)
}
})
client.quit((err, reply) => {
if(!err){
console.log(reply);
}else{
console.log(err);
}
})
})
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}!`);
});
Also this is my first question on stackoverflow so if I could improve how I'm asking or formatting my question I would appreciate feedback on that
It should be
// ....
const history = JSON.stringify(req.body.history) ?? null;
// ....
client.hset(uuid, "history", history);
// ....
Because hset takes parameters as
HSET key field value [field value ...]
so parameters should be odd (key and field-value pairs)
my socket creates problem when frontend loads before the server,
My problems are
1.I get same the socketid from the cookies of multiple clients
2.I get only one client who is connected with multiple socketids from the server
3.When I get this problem, my API calls will not work and I won't get any data from my database
I also get this problem when I restart the server, and when I refresh the frontend multiple times with different clients
my server side code
const mongoose = require("mongoose");
express = require("express");
app = express();
bodyParser = require("body-parser");
cookieParser = require("cookie-parser");
cors = require("cors");
user = require("./routes/user");
message = require("./routes/message");
http = require("http");
server = http.createServer(app);
io = require("socket.io")(server);
var userdata = require("./controllers/user");
mongoose
.connect(process.env.DATABASE, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log("DB CONNECTED");
})
.catch((err) => console.log(err));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(cors());
app.use(express.json());
app.use("/use", user);
app.use("/use", message);
let users = [];
io.on("connection", (socket) => {
socket.on("done", () => {
let userdata = require("./controllers/user");
console.log("connected");
userdata.userdata &&
users.push({ userid: userdata.userdata._id, socketid: socket.id });
console.log(users);
});
socket.broadcast.emit("message");
socket.on("more", function (c) {
console.log(c.a, c.b);
let d = users.find((s) => s.userid === c.b);
if (d) {
return io.to(d.socketid).emit("message", c);
}
});
socket.on("disconnect", () => {
console.log(socket.id);
if (users) {
for (let e = 0; users.length; e++) {
if (users[e] && users[e].socketid === socket.id) {
return users.splice(e, 1);
}
}
}
console.log(users);
return console.log("disconnected");
});
});
// app.use();
const port = process.env.PORT || 8000;
server.listen(port, () => {
console.log(`app is running at ${port}`);
});
I found that my problem is caused by userdata, when I had deleted everything related to userdata, I didn't get any problem even when the server is reloaded.
Here userdata comes from a middileware called isSignedIn,this middleware is called before every API call from this webpage, so userdata gets updated frequently by the frontend code.This is my isSignedIn function
exports.isSignedIn = async (req, res, next) => {
const header = req.headers["authorization"];
const token = header && header.split(" ")[1];
if (!token) return res.json("no token");
jwt.verify(token, "jsdhbcjsd", (err, User) => {
if (err) return res.json(`${err} not signedin`);
req.User = User;
exports.userdata = User;
next();
});
};
I tried to call isSignedIn() instead of importing userdata, which would be lot better, but I was getting an error from the headers, so I couldn't call this function.
error I get when I call this function isSignedIn()
Promise {
<rejected> TypeError: Cannot read property 'headers' of undefined
at exports.isSignedIn (D:\message\backend\controllers\user.js:86:22)
it tells about this line
const header = req.headers["authorization"];
I made sure that the socket gets connected in the frontend only after calling the APIs using await,so that the userdata gets updated before connecting to the socket.I had tested it in the console,socket gets connected only after calling APIs
async componentDidMount() {
//my API calls
await this.friends(token);
await this.findfriends(token);
//connect the socket
this.start();
this.recieve();
}}
My frontend code
const client = require("socket.io-client");
var socket
export default class Home extends Component {
constructor(props) {
super(props);
this.start = this.start.bind(this);
this.send = this.send.bind(this);
this.recieve = this.recieve.bind(this);
this.friends= this.friends.bind(this);
this.findfriends= this.findfriends.bind(this);
}
start(){
socket=client("http://localhost:8000");
}
send(){
socket.emit("more", c)
}
recieve(){
socket.on("message", c)
}
async componentDidMount() {
//my API calls
await this.friends(token);
await this.findfriends(token);
//connect the socket
this.start();
this.recieve();
}}
render(){
return(my data)
}
}
After thinking for a while about requesting headers,which isn't possible, I thought, why couldn't I get userid from the socket when just it gets connected, then I tried this code, it worked perfectly fine
client side
start = () => {
socket = client("http://localhost:8000");
socket.on("connect", () => {
return socket.emit("userinfo", this.state.User._id);
});
};
server side
socket.on("userinfo", function (user) {
users.push({ userid: user, socketid: socket.id });
console.log("C O N N E C T E D");
});
You can't reassign exports.userdata = User; in middleware. That will affect every single request that uses those exports so they will all end up looking at the same userdata, no matter which user they are. That's the source of your confusion. There's only one exports object for each module and everyone who uses that module sees the same exports object. So, you can't use exports for request-specific data.
I see you are already assigning req.User = User. That is an appropriate place to put request-specific data and other users of that data in the processing of the request should get the data from req.User, not from the exported object. That will keep the data separate for each request and each user.
I want to build a NodeJS based API that is backed with a pub-sub paradigm with e.g. Kafka. Here is a skeleton of what I want to do.
const express = require('express')
const serverApp = express()
serverApp.get('/book/:bookId', (req, res) => {
producer.send(JSON.stringify({
action: 'get',
message: req.params.bookId
}))
consumer.on('message', (data) => {
res.status(200).send(JSON.parse(data))
})
})
With the option above, the first invocation works but, the subsequent ones keep failing with ERR_HTTP_HEADERS_SENT.
Keeping the consumer.on outside of serverApp.get will need to have the req and res co-ordinated.
How do I implement such an API?
For example as skeleton
const express = require('express')
const serverApp = express()
const responses = Object.create(null);
consumer.on('message', (data) => {
const result = JSON.parse(data)
const res = responses[result.replyId]
res.status(200).send(result)
});
serverApp.get('/book/:bookId', (req, res) => {
const replyId = Math.random().toString(36).substr(2);
responses[replyId] = res;
producer.send(JSON.stringify({
action: 'get',
replyId,
message: req.params.bookId
}))
})
I have a small api I have built using Node.js and express.
I am trying to create a logger and I need log the request body AND response body.
app.use((req, res) => {
console.log(req);
res.on("finish", () => {
console.log(res);
});
});
"express": "^4.16.3",
However, i am not able to find the body in the req or res object. Please tell me how i can get them. thanks.
For res.body try the following snippet:
const endMiddleware = (req, res, next) => {
const defaultWrite = res.write;
const defaultEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(new Buffer(restArgs[0]));
defaultWrite.apply(res, restArgs);
};
res.end = (...restArgs) => {
if (restArgs[0]) {
chunks.push(new Buffer(restArgs[0]));
}
const body = Buffer.concat(chunks).toString('utf8');
console.log(body);
defaultEnd.apply(res, restArgs);
};
next();
};
app.use(endMiddleware)
// test
// HTTP GET /
res.status(200).send({ isAlive: true });
You need body-parser that will create body object for you in your request. To do that
npm install body-parser
var bodyParser = require('body-parser')//add this
app.use(bodyParser())//add this before any route or before using req.body
app.use((req, res) => {
console.log(req.body); // this is what you want
res.on("finish", () => {
console.log(res);
});
});
Ran into this problem but didn't like the solutions. An easy way is to simply wrap the original res.send or res.json with your logger.
Put this as middleware before your routes.
app.use(function responseLogger(req, res, next) {
const originalSendFunc = res.send.bind(res);
res.send = function(body) {
console.log(body); // do whatever here
return originalSendFunc(body);
};
next();
});
https://github.com/expressjs/express/blob/master/lib/response.js
res.send has signature of function(body) { return this; }
Here is a working example using the built in PassThrough stream. Remember to use the express.json() built in middleware to enable request body parsing.
After that, you need to intercept all writes to the response stream. Writes will happen on calling write or end, so replace those functions and capture the arguments in a separate stream.
Use res.on('finish', ...) to gather all the written data into a Buffer using Buffer.concat and print it.
const express = require('express');
const { PassThrough } = require('stream')
const app = express();
app.use(express.json());
app.use((req, res, next) => {
const defaultWrite = res.write.bind(res);
const defaultEnd = res.end.bind(res);
const ps = new PassThrough();
const chunks = [];
ps.on('data', data => chunks.push(data));
res.write = (...args) => {
ps.write(...args);
defaultWrite(...args);
}
res.end = (...args) => {
ps.end(...args);
defaultEnd(...args);
}
res.on('finish', () => {
console.log("req.body", req.body);
console.log("res.body", Buffer.concat(chunks).toString());
})
next();
})
app.use('/', (req, res) => {
res.send("Hello");
});
app.listen(3000);
install npm install body-parser
and use this snippet,
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// create application/json parser
var jsonParser = bodyParser.json()
to get json response
app.use(jsonParser, function (req, res) {
console.log(req.body); // or console.log(res.body);
})
There is ready made module https://www.npmjs.com/package/morgan-body
const express = require('express')
const morganBody = require("morgan-body")
const bodyParser = require("body-parser")
const app = express()
const port = 8888
// must parse body before morganBody as body will be logged
app.use(bodyParser.json());
// hook morganBody to express app
morganBody(app, {logAllReqHeader:true, maxBodyLength:5000});
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Hi was looking for same as complete log of request and response as middleware in express js. Found the solution as well w
/*Added by vikram parihar for log */
const moment = require('moment');
const rfs = require("rotating-file-stream");
const geoip = require('geoip-lite');
const { PassThrough } = require('stream')
let path = require('path');
const accessLogStream = rfs.createStream('access.log', {
interval: '1M', // rotate daily
compress: true,
path: path.join(__dirname, '../../log')
});
module.exports = function (req, res, next) {
try {
let geo = geoip.lookup(req.ip);
let country = geo ? geo.country : "Unknown";
let region = geo ? geo.region : "Unknown";
let log = {
"time": moment().format('YYYY/MM/DD HH:mm:ss'),
"host": req.hostname,
"ip": req.ip,
"originalUrl": req.originalUrl,
"geo": {
"browser": req.headers["user-agent"],
"Language": req.headers["accept-language"],
"Country": country,
"Region": region,
},
"method": req.method,
"path": req.path,
"url": req.url,
"body": req.body,
"params": req.params,
"query": req.query,
"response": {
"body": res.body
}
};
const defaultWrite = res.write.bind(res);
const defaultEnd = res.end.bind(res);
const ps = new PassThrough();
const chunks = [];
ps.on('data', data => chunks.push(data));
res.write = (...args) => {
ps.write(...args);
defaultWrite(...args);
}
res.end = (...args) => {
ps.end(...args);
defaultEnd(...args);
}
res.on('finish', () => {
log.response.body = Buffer.concat(chunks).toString()
accessLogStream.write(JSON.stringify(log) + "\n");
})
} catch (error) {
console.log(error)
next(error)
}
next();
}