Access Socket.IO from Express.js controller? - node.js

I believe I have socket.io setup properly in the main file (server.js) of an Express app. How do I access socket.io from a controller to emit an event as part of a controller action?
I tried the following based on a similar post, but I am getting an error saying that socket is not defined. Any help will be greatly appreciated.
Similar post:
Socket.io emit from Express controllers
server.js:
'use strict';
var express = require('express'),
path = require('path'),
fs = require('fs'),
mongoose = require('mongoose'),
http = require('http'),
socketio = require('socket.io');
/**
* Main application file
*/
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var config = require('./lib/config/config');
var db = mongoose.connect(config.mongo.uri, config.mongo.options);
// Bootstrap models
var modelsPath = path.join(__dirname, 'lib/models');
fs.readdirSync(modelsPath).forEach(function (file) {
if (/(.*)\.(js$|coffee$)/.test(file)) {
require(modelsPath + '/' + file);
}
});
// Populate empty DB with sample data
require('./lib/config/dummydata');
// Passport Configuration
var passport = require('./lib/config/passport');
// Setup Express
var app = express();
// Setup socket.io
var server = http.createServer(app);
var io = socketio.listen(server);
require('./lib/config/express')(app);
require('./lib/routes')(app);
// Start server
// Call listen on server instead of app to setup socket.io. See this post:
// https://stackoverflow.com/questions/21173182/why-isnt-my-angularjs-express-socket-io-app-serving-the-socket-io-js-file/21175137#21175137
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %s:%d, in %s mode', config.ip, config.port, app.get('env'));
});
io.sockets.on('connection', function(socket) {
console.log('socket connected');
socket.emit('message', {
message: 'You are connected to the backend through the socket!'
});
});
// Expose app
exports = module.exports = app;
routes.js:
'use strict';
var api = require('./controllers/api'),
index = require('./controllers'),
users = require('./controllers/users'),
items = require('./controllers/items'),
session = require('./controllers/session'),
middleware = require('./middleware');
/**
* Application routes
*/
module.exports = function(app, socket) {
app.route('/api/items')
.get(items.index)
.post(items.create(socket));
// All undefined api routes should return a 404
app.route('/api/*')
.get(function(req, res) {
res.send(404);
});
// All other routes to use Angular routing in app/scripts/app.js
app.route('/partials/*')
.get(index.partials);
app.route('/*')
.get( middleware.setUserCookie, index.index);
};
items.js (controller):
'use strict';
var mongoose = require('mongoose'),
Item = mongoose.model('Item');
exports.create = function(socket) {
return function(req, res) {
// write body of api request to mongodb
socket.emit();
}
}

Related

How to export models in the form of middle ware in main server.js and write routes for tables in separate model.js file

I am a newbie in node.I have created a server file to connect mongoDB and wrote routes in the same. Created a model.js for table attributes.I want to write a route for my other tables.
https://codingthesmartway.com/the-mern-stack-tutorial-building-a-react-crud-application-from-start-to-finish-part-2/
Taken reference from here. But want to create a seperate file for connection and add module for tables
This is my server.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const todoRoutes = express.Router();
const PORT = 4000;
let Todo = require('./todo.model');
app.use(cors());
app.use(bodyParser.json());
app.use('/todos', todoRoutes);
mongoose.connect('mongodb://127.0.0.1:27017/todos', {
useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established
successfully");
})
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
todoRoutes.route('/').get(function(req, res) {
Todo.find(function(err, todos) {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
this routes are in this file i want to export it from other model.js
If you want to put route in another file,i would suggest you to make a new folder route and then inside it make a new file by route name(say createUser.js).
In this server.js file only use
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const PORT = 4000;
let Todo = require('./todo.model');
app.use(cors());
app.use(bodyParser.json());
app.use('/todos', todoRoutes);
mongoose.connect('mongodb://127.0.0.1:27017/todos', {
useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established
successfully");
})
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
export default app;
And in another file inside route folder use the require imports and define the route here.
const todoRoutes = express.Router();
todoRoutes.route('/').get(function(req, res) {
Todo.find(function(err, todos) {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
module.exports=todoRoute;
Furthur you can import this route in any model.js and use it for implementation of logic.
Note-: You can also use a third folder controllers and implement the route logic there since it is the best practice to not write logic on route but use controller file for it.Also you can separate the DB connection login in another file.

socket.io emit when someone call the API

I have a small project with NodeJS Express server and Angular2 frontend. The server has an API interfaces. The main part of this is: /api/alert. I want to do the following: If the /api/alert get an request then socket.io broadcast an event to all connected clients.
My server structure is the following:
server.js
var http = require('http'),
express = require('express'),
app = module.exports.app = express(),
port = process.env.PORT || 3000,
mongoose = require('mongoose'),
bodyParser = require('body-parser'),
db = require('./config/db'),
path = require('path');
mongoose.Promise = global.Promise;
mongoose.connect(db.url);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'dist')));
var routes = require('./server/routes/index');
routes(app);
var server = http.createServer(app);
var io = require('socket.io')(server);
server.listen(port);
console.log('Server started on: ' + port);
server/routes/index.js
const deviceRoute = require('./devicesRoute');
const alertRoute = require('./alertsRoute');
module.exports = function(app) {
deviceRoute(app);
alertRoute(app);
}
server/routes/alertRoute.js
'use strict';
module.exports = function(app) {
var alertsService = require('../services/alertsService');
app.route('/api/alert')
.post(alertsService.createAlert);
};
server/service/alertService.js
'use strict';
exports.createAlert = function(req, res) {
// do something in database
// I want to broadcast to all client HERE
};
I can't pass the io and server variables to the function (from server.js). How can I do that? What is the easiest way?
Thank you!
First you would want to export both the app and server objects from server.js and pass your socket to your response in middleware as follows:
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(server);
app.use(function(req, res, next){
res.io = io;
next();
});
...
module.exports = {app: app, server: server};
You can then require the server instance you created in server.js (depending on where you are requiring it from) as
var server = require('../server').server;
Since you added socket.io to the response object, you can use it in your services as
'use strict';
exports.createAlert = function(req, res) {
// do something in database
// I want to broadcast to all client HERE
res.io.emit("broadcast", "clients");
};

req.body undefined on server side

I am working on app which uses node, express, mysql on server side. i have written serveral APIs on server.js file and when i am trying to access those using Postman then req.body is always undefined.
this is my server.js configuration.
var express = require('express');
var mysql = require('mysql');
var cors = require('cors');
var bodyParser = require('body-parser');
var wrench = require("wrench");
var fs = require('fs');
var path = require("path");
var mkdirp = require('mkdirp');
var walk = require('walk');
var fse = require('fs-extra');
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
var crypto = require('crypto');
app.use(cors());
app.use(bodyParser.urlencoded({limit: '50mb',extended: false}));
app.use(bodyParser.json({limit: '50mb'}));
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'pass',
database: 'dbname'
});
connection.connect(function(err) {
if (!err) {
console.log("Database is connected ... \n\n");
} else {
console.log("Error connecting database ... \n\n");
}
});
app.post('/urlreq', function(req, res){
console.log(req.body);
}
app.listen(3000, function(){
console.log("Rest Demo Listening on port 3000");
});
When i am trying send something in body in Postman then req.body is coming empty on server side.
If you are sending multipart/form-data, it doesn't work because bodyparser doesn't handle this body type.
In this case adding the following line should fix it:
app.use(multipartMiddleware);
Form the docs:
multipart/form-data is the default encoding a web form uses to transfer data
Try add:
var express = require('express');
var app = express();
[...]
// Last stack
app.listen(3000, function(){
console.log("Rest Demo Listening on port 3000");
});
You can use as a middleware also. Also listen on a port. add following lines in your code -
var app = express();
app.use(function(req, res, next) {
console.log('Current User:', req.body);
next();
});
app.post('/url', function(req,res){
console.log(req.body)
});
app.listen(3000, function(){
console.log('Express server listening on port 3000');
});

Socket.IO and express routes

I would like to use socket.io and express routes and I have the following code:
app.js
var
http = require('http'),
path = require('path'),
passport = require('passport'),
userpassport = require('./lib/strategies/local'),
githubpassport = require('./lib/strategies/github'),
flash = require('connect-flash'),
express = require('express'),
logger = require('morgan'),
bodyParser = require('body-parser'),
cookieParser = require('cookie-parser'),
session = require('express-session'),
errorhandler = require('errorhandler'),
csrf = require('csurf'),
favicon = require('serve-favicon'),
sockets = require('./lib/socket'),
app = express();
var routes = require('./routes')();
app.get('/', routes.index);
var server = http.createServer(app).listen(app.get('port'), function () {
var io = require('socket.io')(server);
io.on('connection', function (iosocket) {
sockets.setSocket(iosocket);
});
});
lib/socket.js
var socket;
exports.setSocket = function(iosocket) {
console.log('setting socket');
socket = iosocket;
}
exports.getSocket = function() {
console.log('getting socket');
return socket;
}
routes/index.js
var sockets = require('../lib/socket');
module.exports = function () {
var routes = {};
routes.index = function (req, res) {
var socket = sockets.getSocket();
socket.on('app/create', function (data) {
console.log('got app create');
});
}
This does not work, I think it's because the setSocket function that appears on app.js runs after the page was loaded, therefore when I getSocket on the route it's not the latest socket (I can console log the given socket on the route, I can see there's a socket there, but I can also see that the setSocket runs afterwards).
How can I solve this?

route structure in nodejs & expressjs

I have following Application structure
/routes
- index.js
dbconfig.js
dbresources.js
server.js
1. Content of /routes/index.js
exports.index = function(req, res){
console.log("Routes Successfully");
sequelize.query("SELECT * FROM users_tbl").success(function(rows) {
res.format({
json: function() {
res.send(rows);
}
});
// res.jsonp(rows);
}).error(function(error) {
console.log(error);
});
};
2. Content of dbresources.js
module.exports = {
database: {
name: "dbproject",
host: "root",
password: ""
}
}
3. Content of dbconfig.js
var Sequelize = require('sequelize')
, mysql = require('mysql');
config = require("./dbresources");
db = config.database;
var sequelize = new Sequelize(db.name, db.host, db.password, {
dialect: 'mysql'
});
4. Content of server.js
var express = require('express')
, http = require('http')
, app = express()
, http = require('http')
, routes = require('./routes')
, path = require('path');
app.configure(function() {
app.set('port', process.env.PORT || 5000);
app.use(express.bodyParser());
app.set(express.methodOverride());
app.set(express.router);
app.use(express.static(__dirname + '/src'));
});
app.get('/user', routes.index);
http.createServer(app).listen(app.get('port'), function(){
console.log("\n\n\tNode (Express) server listening on port " + app.get('port'))
});
When i am running my apps using node and fire localhost:5000/user. It shows me following error.
ReferenceError: sequelize is not defined
The error is exactly what's wrong. You're using sequelize without defining it first it in /routes/index.js. If it's the var you've created in dbconfig, you first need to expose it like so:
// The rest of the code...
exports.sequelize = sequelize;
and import it in /routes/index.js like so:
var sequelize = require('./dbconfig').sequelize;
// The rest of the code...

Resources