Using socket.io with express.js controller - node.js

I am trying to use socket.io with controller functions in express.js, but the socket.on is not calling into the io.on() in server.js
// at server.js
const postRoute = require('./routes/postReqRouter')
io.on('connection', function (socket) {
console.log('=====SOCKET Connected======', socket.id)
socket.on('taskDataSOCK', function (data) {
console.log('====TaskData Found====', data)
io.emit('taskDataSOCK', { data })
})
}
app.use(function (req, res, next) {
res.io = io
next()
})
app.use('/api/post', postRoute)
// postReqRouter.js
router.route('/get-all-data').post(contoller.getData)
module.exports = router
// at controller.js
exports.getData = (req, res) => {
/// `enter code here`
res.io.emit(‘'taskDataSOCK', { data })
}

The io.on('connection') is called when a client is connected you can connect to the same socket server using client (frontend) or from another nodejs app see here

Related

how to implement middleware in socket.io like express in NodeJS?

How to implement middleware like this in socket.io? Please help
EXPRESS APP
var myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
app.use(myLogger)
app.get('/', function (req, res) {
res.send('Hello World!')
})
SOCKET APP (I am using express pattern but its not working)
var myLogger = function (data,next) {
console.log('DOING DATA VALIDATION...')
next()
}
io.use(myLogger)
io.on('someEvent/', function (data, callback) {
callback('Hello World!')
})
Error : next() is not define!
app.use(function (req, res, next) {
req.io = io;
next();
});
This assigns a socket object to every request.
If somebody's still wondering.
To use middleware on all sockets:
io.use((socket, next) => {
// isValid is just a dummy function
if (isValid(socket.request)) {
next();
} else {
next(new Error("invalid"));
}
});
This example is from the official docs of socket.io
To use a middleware for a specific client:
io.on('connection', async (client) => {
client.use((socket, next) => {
console.log(`got event: ${socket[0]} in client middleware, moving on with next() just like in express`)
next()
});
// rest of your code
newConnection(client)
})

How to mock express in nodejs when express app is located inside function?

I have httpListener.ts, which looks like this:
export function startListening() {
const app = express();
app
.use(bodyParser.json())
.post('/home/about', func1)
.get('/user/product/:id', func2)
.use(function (req, res) {
res.status(404).send(`no routing for path ${req.url}`);
})
.listen(httpListenerConfig.port, () => {
console.log('listening..');
});
}
and I have to write unit tests for func1 and func2 (these functions are private),I want to invoke them using fake http request..
any idea?
You can use framework like superTest to test the http request. SuperTest needs the express app and so I am exporting the app.
I am assigning app.listen to server so that the server can be closed (server.close) after the test.
httpListener.js
var express = require('express');
function startListening() {
const app = express();
app
.get('/home/about', func1)
.get('/user/product/:id', func2)
.use(function (req, res) {
res.status(404).send(`no routing for path ${req.url}`);
})
var server = app.listen(3001, () => { //so the server can be closed after the test
console.log('listening..');
});
module.exports = server;
}
function func1 (req, res) {
res.status(200).send('this is home - about page');
}
function func2 (req, res) {
res.status(200).send('this is product page');
}
startListening();
httpListener-test.js
var request = require('supertest');
describe('loading express', function () {
var server;
beforeEach(function () {
server = require('./httpListner.js');
});
afterEach(function () {
server.close();
});
it('responds to /home/about', function test(done) {
request(server)
.get('/home/about')
.expect(200) //test status
.expect('this is home - about page', done); //test the response string
});
});
To test more on func1 and func2, you have to export them so it is available to test.

'Sharing' object between NodeJS modules

I'm new to NodeJS development and I'm doing some tests with the socket.io library. Basically, what I want to do is to stablish a socket.io connection between the clients (Angular 6 web app) and the server and broadcast a message when a new user connects.
Right now, the code is quite simple, and this is what I have:
app.js
var express = require('express');
var http = require('http');
var socketIO = require('socket.io');
// Routes
var twitterRoutes = require('./routes/user');
var app = express();
var server = http.Server(app);
var io = socketIO(server); // <== THIS OBJECT IS WHAT I WANT TO USE FROM THE ROUTES
[ ... ]
io.on('connect', (socket) => {
console.log('New user connected');
socket.on('disconnect', (reason) => {
console.log('User disconnected:', reason);
});
socket.on('error', (err) => {
console.log('Error in connection: ', err);
});
});
I want to use the io object inside the user route, but I don't know how to do it:
routes/user.js
var express = require('express');
var config = require('../config/config');
var router = express.Router();
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
// I WANT TO BROADCAST THE NEW LOGGED USER USING io.broadcast.emit, BUT DON'T KNOW HOW
// <=====
});
How could I do it? Thanks in advance,
Not sure if it is the best way but you could share things between request handlers using middleware
// define and use a middleware
app.use(function shareIO(req, res, next) {
req.io = io;
next();
})
Then you could use req.io inside request handlers.
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
req.io.emit('event')
});
You could do what you want by injecting your IO var in a function
// app.js
var app = express();
var server = http.Server(app);
var io = socketIO(server);
server.use(require('./router')(io))
...
// router.js
module.exports = function makeRouter(io) {
var router = express.Router();
router.post('/login', (req, res, next) => {
// do something with io
}
return router
}
I don't know if it's the best practice, but I've assigned the io object to a property of the global object, and I can access it from everywhere all across the application. So this is what I did:
app.js
var io = socketIO(server);
global.ioObj = io;
routes/user.js
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
if (global.ioObj) {
global.ioObj.sockets.clients().emit('new-message', { type: 'message', text: 'New user has logged in' });
}
});

How use socket.io in express routes with node.js

I'm using Express with Socket.io in the server side but i can't use out of app.js, i need how to use SocKet.io in Express routes.
app.js
...
let http = require('http').Server(app);
let io = require('socket.io')(http);
io.on('connection', (socket) => {
console.log('user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('message', (message) => {
console.log("Message Received: " + message);
io.emit('message', {type:'new-message', text: message});
});
});
...
this work ok, but i have other routes where configure my methods, POST, GET ... EX
routesActividad.js
...
function http(){
this.configActividad= function(app){
// get actividades by id
app.get('/actividad/:NUM_ID_EMPLEADO', function(req, res) {
//... code here...//
.then(function (actividad) {
res.json(actividad);
}).catch(error => res.status(400).send(error));
})
app.post('/actividad/', function(req, res){
// code here //
})
app.put('/actividad/', function(req, res){
// code here //
})
}
}
module.exports = new http();
how i can use socket in routesActividad.js and other routes like this, for use emit or scoket.on y this routes
app.js
...
var routesActividad = require('./routes/routesActividad');
routesActividad.configActividad(app);
// more routes
...
thanks
Hello you just need to pass the IO instance by parameter to your external module:
app.js
let http = require('http').Server(app);
let io = require('socket.io')(http);
let actividad = require('routesActividad')(io);
routesActividad.js:
function http(io){
//put the IO stuff wherever you want inside functions or outside
this.configActividad= function(app){
// get actividades by id
app.get('/actividad/:NUM_ID_EMPLEADO', function(req, res) {
//... code here...//
.then(function (actividad) {
res.json(actividad);
}).catch(error => res.status(400).send(error));
})
app.post('/actividad/', function(req, res){
// code here //
})
app.put('/actividad/', function(req, res){
// code here //
})
}
}
module.exports = http; //Removed new statement

NodeJS, socketIO, multiple files

I'm a little bit confused;
I would like to use socketIO on NodeJS app.
I've created this (pseudo)code:
//server.js
var app = express();
//some code...
var router = require('./app/router');
app.use(router);
var server = app.listen(appConfig.app.port, function () {
var port = server.address().port;
});
var io = require('socket.io')(server);
io.on('connection', function (client) {
console.log('Client connected...');
client.on('join', function (data) {
console.log(data);
});
});
//client.js
var socket = io.connect('http://localhost:5555');
socket.on('connect', function(data) {
socket.emit('join', 'Hello World from client');
});
Everything is fine. But !
At now, I would like to emit event in another file.
I have router and POST request. I want to emit event on POST request (request handler is in another file).
//router.js
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
res.json(data)
});
};
);
I have to initialize router before start server, but I have to pass server to IO... How pass IO to router ?
You can try this
//server.js
var app = express();
//some code...
var io;
var getIOInstance = function(){
return io;
};
var router = require('./app/router')(getIOInstance);
app.use(router);
var server = app.listen(appConfig.app.port, function () {
var port = server.address().port;
});
io = require('socket.io')(server);
io.on('connection', function (client) {
console.log('Client connected...');
client.on('join', function (data) {
console.log(data);
});
});
//router.js
module.exports = function(getIOInstance){
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
getIOInstance().sockets.emit(...)
res.json(data)
});
};
return router;
);
This solution will work if you want to 'notify' all connected clients.
If you need to notify only a specific client, then I will advise you to use an event-emitter module in order to communicate these events and not share your socket instances across multiple files.
In router.js you can do something like:
//router.js
module.exports = function(io) {
var router = //What you declared it to be
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
res.json(data)
});
};
);
return router;
}
//server.js
//Change this line to be like the one below
var router = require('./app/router');
//.........
//.......
//Desired way
var router = require('./app/router')(io);
The answer of #jahnestacado does the job, but in case you already have an existing code base, then you need to change the structure of each file, where you might need the socket.io object, to pass it in as an argument.
A better way to do it then, would be:
To create the getIO() function—just as #jahnestacado did—, where you instantiate the io object (inside server.js), and export it.
var io;
exports.getIO = () => io;
Then require it wherever you need it. But make sure to execute the function only when you need it. Typically inside your controller function:
const getIO = require('../server').getIO;
exports.updateSAE = (req, res) => {
let io = getIO();
io.emit();
// rest of your controller function code
}
Note that I did not call the getIO function outside the controller function. For example, the following would probably not work:
const getIO = require('../server').getIO;
var io = getIO();
exports.updateSAE = (req, res) => {
io.emit();
// rest of your controller function code
}
Simply because the socket.io object could have not been initialized when you call the function, thus returning undefined.

Resources