I'm trying to figure out how to use DialogFlow with express/bodyParser and the node.js library v2 functions without Firebase (on my own server). I have it working with the request/response JSON data, but I can't figure out what I need to do to use the node.js library function dialogflow(). Here's a snippet of what I have that's working with the JSON data:
const {config} = require('./config');
const https = require('https');
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const options = {
key: fs.readFileSync(config.SSLDIR + 'privkey.pem'),
cert: fs.readFileSync(config.SSLDIR + 'cert.pem'),
ca: fs.readFileSync(config.SSLDIR + 'chain.pem')
};
const eapp = express();
eapp.disable('x-powered-by');
eapp.use(bodyParser.urlencoded({extended: true}));
eapp.use(bodyParser.json());
const server = https.createServer(options, eapp).listen(config.LISTEN_PORT, () => {
console.log(`API listening on port ${config.LISTEN_PORT}. Ctrl-C to end.`);
});
server.on('error', (e) => {
console.log(`Can't start server! Error is ${e}`);
process.exit();
});
// I have an Agent class that reads the request object and handles it
eapp.post("/actions", (request, response) => {
const agent = new Agent(request, response);
agent.run();
return;
});
eapp.all('*', (request, response) => {
console.log("Invalid Access");
response.sendStatus(404);
});
The only solution posted online that I could find said to use the following code:
const express = require('express');
const bodyParser = require('body-parser');
const { dialogflow } = require('actions-on-google');
const app = dialogflow();
express().use(bodyParser.json(), app).listen(3000);
But I'm confused about:
DialogFlow fulfillment requires an https endpoint, so don't I have
to create an https server like I did?
How can I integrate this example into what I've already done to stop
using the JSON data and start using the node.js functions from
app=dialogflow() in the library?
The app instance created using the dialogflow function can be used like an Express Request handler function. Thus, you can call it with the Express request and response object to handle the request.
In the run function for your Agent class, you can do something like
run() {
const request = ...; // Express request object
const response = ...; // Express response object
const app = ...; // app instance created using the dialogflow function
app(request, response); // call app with the Express objects
}
Then when you deployed this server to a public HTTPS endpoint, you can set the fulfillment url in Dialogflow to something like:
https://subdomain.domain.tld/actions where /actions was the post endpoint you listened to in the code.
In the end, it was very simple. I just needed to include the app in bodyparser:
eapp.use(bodyParser.json(), app);
Related
I'm making a basic restaurant ordering web app for fun/learning purposes using node/express for my backend and react as my frontend. I've based my app on a mix of various YT tutorials including the ones Dave Gray to structure my project.
Currently I'm at the stage where I'm trying to implement notifications using SocketIO (the idea that the server will push notifications down to the clients to notify them of certain events such as an order being made).
My current progress is here: https://github.com/kevin-rph-lee/noodlebox/tree/socket-notifications
The issue I'm having is I'm trying to figure out the best way to pass my SocketIO object down to one of my controllers (specifically the orders controller).
My current structure is:
server.js --> orders.js (route) --> ordersController.js (controller)
Currently in my main server.js file I have initialized the io object for SocketIO (as seen below)
require('dotenv').config();
const WebSocketServer = require("ws").Server
var http = require("http")
const express = require('express');
const path = require('path');
const PORT = process.env.PORT || 3001;
const app = express();
const morgan = require('morgan');
const cors = require('cors');
const corsOptions = require('./config/corsOptions');
const credentials = require('./middleware/credentials');
const cookieParser = require('cookie-parser');
// Creating a new socketio server
const server = require('http').createServer(app);
const io = require('socket.io')(server);
//Numbers of users connected. Initially 0
let clientsConnected = 0
io.on('connection', function(socket){
//Client connecting, incrementing client counter
clientsConnected++
console.log('Client connected. Total clients connected ' + clientsConnected)
//When a message is recieved from a client, echo it to all other clients connected
socket.on("message from client", (arg) => {
console.log('reieved')
console.log(arg)
// socket.broadcast.emit('message to client', arg)
// socket.to(1).emit('message to client', 'enjoy the game')
io.in(1).emit('message to client', 'enjoy the game')
});
socket.on("join", (userID) => {
socket.join(userID)
console.log('Rooms:')
console.log(socket.rooms)
});
socket.on("leave", (userID) => {
socket.leave(userID)
console.log('Rooms:')
console.log(socket.rooms)
});
//Deincrement the counter when the client disconnects
socket.on("disconnect", (reason) => {
clientsConnected--
console.log('Client connected. Total clients connected ' + clientsConnected)
});
})
// PG database client/connection setup
const { Pool } = require('pg');
const dbParams = require('./lib/db.js');
const db = new Pool(dbParams);
db.connect();
// Load the logger first so all (static) HTTP requests are logged to STDOUT
// 'dev' = Concise output colored by response status for development use.
// The :status token will be colored red for server error codes, yellow for client error codes, cyan for redirection codes, and uncolored for all other codes.
app.use(morgan('dev'));
app.use(credentials);
app.use(cors(corsOptions));
app.use(express.json()); // => allows us to access the req.body
//middleware for cookies
app.use(cookieParser());
if (process.env.NODE_ENV === 'production') {
//server static content
//npm run build
app.use(express.static(path.join(__dirname, 'client/build')));
}
console.log(__dirname);
console.log(path.join(__dirname, 'client/build'));
// Separated Routes for each Resource
const usersRoutes = require('./routes/users');
const refreshRoutes = require('./routes/refresh');
const menuItemsRoutes = require('./routes/menuItems');
const ordersRoutes = require('./routes/orders');
// Resource routes
app.use('/users', usersRoutes());
app.use('/refresh', refreshRoutes());
app.use('/menuItems', menuItemsRoutes());
app.use('/orders', ordersRoutes());
// All other GET requests not handled before will return our React app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '/client/build/index.html'));
});
server.listen(PORT);
I am now trying to figure out how to pass the io object down to my orders route, and then from the route to the controller.
Within server.js, to pass io down to the route it was thinking it would be something like...
app.use('/orders', ordersRoutes(io));
But within the order route itself I get stuck
order.js
const express = require('express');
const router = express.Router();
const ordersController = require('../controllers/ordersController')
const verifyJWT = require('../middleware/verifyJWT')
const verifyRoles = require('../middleware/verifyRoles');
module.exports = () => {
//Get order
router.route('/')
.get(verifyJWT, verifyRoles('user', 'admin'),ordersController.getOrders)
//Create order
router.route('/')
.post(verifyJWT, verifyRoles('user', 'admin'), ordersController.createOrder)
return router;
};
To receive the io object from server.js I'm thinking I would need to modify the module.exports line so it would look like:
module.exports = (io) = {
but at that point I'm stuck on how I can pass it down one more layer from the route file to the controller file. The idea is I want the io functionality (e.g broadcasting a SocketIO message) to be available to me within the controllers file. In particular I want the ability to broadcast a message when a certain axios request is made from a connected client (e.g broadcast a SocketIO message when an axios POST request is made to create an order).
I was hoping someone could help me out with a potential way to move forward, or let me know if I'm going down the completely wrong path.
Thank you
I am trying to make a simple server with socket.io and express and connect to it through a website.
when i followed a tutorial on socketio with localhost, everything worked fine, but when i put the server on a vserver, and tried to connect to it, i got this error:
Failed to load resource: net::ERR_SSL_PROTOCOL_ERROR
as well as:
GET https://54.53.0.254:47185/socket.io/?EIO=4&transport=polling&t=O09jjrs net::ERR_SSL_PROTOCOL_ERROR
here is my server code:
const express = require('express');
const app = express();
const server = app.listen(47185);
const socket = require('socket.io');
const io = socket(server)
console.log('server running on port 47185');
io.sockets.on('connection', newConnection);
function newConnection(socket) {
console.log('new connection: ' + socket.id);
socket.on('input', inputLog)
function inputLog(data) {
socket.broadcast.emit('input', data);
console.log(data);
}
}
and here is my client code (this is all that relates to socket.io, the rest is just for the website)
var options = {
rejectUnauthorized:false
}
var socket;
socket = io.connect('89.58.0.199:47185', options);
socket.on('input', foreignInput)
function foreignInput(data) {
terminal_animate('\n' + data)
}
i have tried many different fixes and googled everything i can think of, and i'm just not sure what the problem is.
can anyone help me out with this issue? thanks in advance.
In the documentation, according to the Client Initialization part, in node.js you should provide the protocol when connecting to the server.
// the following forms are similar
const socket = io("https://server-domain.com");
const socket = io("wss://server-domain.com");
const socket = io("server-domain.com"); // only in the browser when the page is served over https (will not work in Node.js)
The first two example shows the secure https/wss as protocol, for that you need to serve the required files from the server, example in the documentation.
With http/ws as protocol it should work, but the communication will not be secure.
The Server Initialization / With Express shows an example to call .listen on the return value of createServer from the http module, with the app given as a parameter.
const express = require("express");
const { createServer } = require("http");
const { Server } = require("socket.io");
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, { /* options */ });
io.on("connection", (socket) => {
// ...
});
httpServer.listen(3000);
With a caution that says:
Using app.listen(3000) will not work here, as it creates a new HTTP server.
good afternoon. I am new to programming sockets in node.js and I need to implement socket.io in a controller of my application. The architecture I have is the following:
The file that starts the server is index.js
const express = require('express');
const app = express();
const port = 3000;
const socketRouter = require('./routes/socket')
app.use(express.json());
//Route
app.use('/socket', socketRouter);
app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
The file where I define the routes is socket.js
const { Router } = require('express');
const { showData } = require('../controllers/socket');
const router = Router();
router.post('/send-notification', showData);
module.exports = router;
And my controller is:
const { response } = require('express');
const showData = (req, res = response) => {
const notify = { data: req.body };
//socket.emit('notification', notify); // Updates Live Notification
res.send(notify);
}
module.exports={
showData
}
I need to implement socket.io in this controller to be able to emit from it but I can't get it to work. Could you tell me how to do it?
Thanks a lot
CLARIFICATION: if I implement socket.io in the main file it works, but I want to have some order and separate things. This is how it works:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.post('/send-notification', (req, res) => {
const notify = { data: req.body };
socket.emit('notification', notify); // Updates Live Notification
res.send(notify);
});
const server = app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
const socket = require('socket.io')(server);
socket.on('connection', socket => {
console.log('Socket: client connected');
});
Move your socket.io code to its own module where you can export a method that shares the socket.io server instance:
// local socketio.js module
const socketio = require('socket.io');
let io;
modules.exports = {
init: function(server) {
io = socketio(server);
return io;
},
getIO: function() {
if (!io) {
throw new Error("Can't get io instance before calling .init()");
}
return io;
}
}
Then, initialize the socketio.js module in your main app file:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
const server = app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
// initialize your local socket.io module
const sio = require('./socketio.js');
sio.init(server);
// now load socket.io dependent routes
// only after .init() has been called on socket.io module
const socketRouter = require('./routes/socket')
app.use('/socket', socketRouter);
Then, anywhere you want to access the socket.io server instance, you can
require("./socketio.js") and use the .getIO() method to get the socket.io instance:
// use correct path to socketio.js depending upon where this module
// is located in the file system
const io = require("../../socketio.js").getIO();
// some Express route in a controller
const showData = (req, res) => {
const notify = { data: req.body };
// send notification to all connected clients
io.emit('notification', notify);
res.send(notify);
};
module.exports= {
showData
};
Note: A typical socket.io usage convention on the server is to use io as the server instance and socket as an individual client connection socket instance. Please don't try to use socket for both. This makes it clear that io.emit(...) is attempting to send to all connected clients and socket.emit() is attempting to send to a single connected client.
Also note that if your route is triggered by a form post where the browser itself sends the form post, then that particular client will not receive the results of io.emit(...) done from that form post route because that browser will be in the process of loading a new web page based on the response of the form post and will be destroying its current socket.io connection. If the form post is done entirely via Javascript using an Ajax call, then that webpage will stay active and will receive the results of the io.emit(...).
You can use the same socket and app (if you need to expose APIs as well) in other files if you want to separate socket messages and REST endpoints by functionality or however you choose to organize it. Here's an example of how this can be done:
Create a new file, let's say controller1.js:
function initialize(socket, app) {
socket.on('some-socket-message', socket => {
// Whatever you want to do
});
app.get('/some-endpoint', (req, res) => {
// whatever you want to do
});
}
module.exports = {initialize}
And then add the following to your controller.js
const controller1 = require('path/to/controller1');
...
// At some point after socket and app have been defined
controller1.initalize(socket, app);
This will be the bases of separating your controller however you want, while still using the same socket connection and API port in all of your controllers. You can also refactor the initialize method into different methods, but that would be at your own discretion and how you want to name functions, etc. It also does not need to be called initalize, that was just my name of preference.
My twilio code is:
const express = require('express');
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/health', (req, res) => {
res.send('ok')
})
// Returns TwiML which prompts the caller to record a message
app.post('/record', (request, response) => {
// Use the Twilio Node.js SDK to build an XML response
const twiml = new VoiceResponse();
twiml.say("Hi!");
// Use <Record> to record the caller's message
twiml.record();
console.log(twiml.toString())
response.send(twiml.toString());
});
// Create an HTTP server and listen for requests on port 3000
app.listen(PORT);
But I want to know the recording ID so I can access the raw file programatically. How would I do that?
To get the recording ID, (RecordingSid), you need to tell Twilio an action URL, with something like this:
twiml.record({
action: '/finished'
});
You can read more here: (https://www.twilio.com/docs/voice/twiml/record#attributes). Also, read about the recordingStatusCallback URL attribute, maybe that's something you need too.
Then, you need to parse the body of this second request Twilio will make to your app.
You can read more about this here: (https://www.twilio.com/blog/2016/07/how-to-receive-a-post-request-in-node-js.html).
For this you can use body-parser, which you can get with npm install body-parser.
The recording ID will be part of the parameters under body.RecordingSid.
Anyway, here is a rough modification of your code, to get started:
// npm install express body-parser
const express = require('express');
const bodyParser = require('body-parser');
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const app = express();
// Tell express to use the body-parser middleware and to not parse extended bodies
app.use(bodyParser.urlencoded({
extended: false
}))
const PORT = process.env.PORT || 3000;
app.get('/health', (req, res) => {
res.send('ok')
})
// Returns TwiML which prompts the caller to record a message
app.post('/record', (request, response) => {
// Use the Twilio Node.js SDK to build an XML response
const twiml = new VoiceResponse();
twiml.say("Hi!");
// Use <Record> to record the caller's message
twiml.record({
action: '/finished'
});
console.log(twiml.toString())
response.send(twiml.toString());
});
app.post('/finished', function (req, res) {
const body = req.body;
res.set('Content-Type', 'text/plain');
res.send(``);
console.log(body);
console.log(body.RecordingSid);
});
// Create an HTTP server and listen for requests on port 3000
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
I hope this helps.
I have a simple app where I'm trying to log to the console (terminal where I started Node, not the the browser console). Express seems to execute the route since I can see the response in my browser.
Also the logging in the app.listen(..) seems to work, but I don't see any logs afterwards.
'use strict';
// 3rd-party dependencies
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const dbSetup = require('./db-setup');
// Application config
const LOCAL_APP_PORT = 8080;
const PUBLIC_APP_PORT = process.env.PUBLIC_APP_PORT || LOCAL_APP_PORT;
global.dbType = process.env.DB_TYPE;
// Sanity check for debugging
console.log("local app port:", LOCAL_APP_PORT);
console.log("public app port:", PUBLIC_APP_PORT);
console.log("db type:", global.dbType);
// Database setup for either MongoDB or Postgres
dbSetup(global.dbType);
// Express middleware
app.use(bodyParser.json()); // for parsing application/json
// Import routes
//const index = require('./routes/index');
//const owner = require('./routes/owner');
//const shop = require('./routes/shop');
//const product = require('./routes/product');
// Set up express routes
app.use('/',(req,res,next) => {
console.log("This is not showing on the terminal.");
res.send("This is sent to the browser");
next();
})
//app.use('/owner', owner);
//app.use('/shop', shop);
//app.use('/product', product);
app.listen(LOCAL_APP_PORT, () => {
console.log('App started ...');
});
EDIT: Solved. Problem was my app was basically available on two ports at the same time. One the the public port however it was not showing any logs...
Terminal screenshot