Issue to add socketio to API Express - node.js

i'm trying to add socket.io on my already existing NodeJS API REST Project.
var express = require('express')
var bodyParser = require('body-parser');
var https = require('https');
var http = require('http');
var fs = require('fs');
var router = require('./route/router');
require('dotenv').config();
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(require('helmet')());
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Authorization,Content-Type');
next();
});
router(app);
if (process.env.PRODUCTION === "false") {
http.createServer(app).listen(8080, function() {
console.log('8080 ok');
});
var io = require('socket.io')(http);
} else {
const options = {
cert: fs.readFileSync('./../../etc/letsencrypt/live/test.com/fullchain.pem'),
key: fs.readFileSync('./../../etc/letsencrypt/live/test.com/privkey.pem')
};
https.createServer(options, app).listen(8443, function() {
console.log('8443 ok');
});
var io = require('socket.io')(https);
}
io.sockets.on('connection', socket => {
console.log('socketio connected');
});
I have no error displayed (server side). But, when I tried on client side, this.socket = io('ws://localhost:8080/');, it's not working at all.
I get GEThttp://localhost:8080/socket.io/?EIO=3&transport=polling&t=NG6_U6i [HTTP/1.1 404 Not Found 1ms] browser console.
It seems that something is not ok with the server, but I can't find what's going on
Any idea ?
Thanks

Try this way, you need to include (I don't know if this is the correct word to use) the express server into the socket.io server.
const express = require('express');
const socketio = require('socket.io');
const port = process.env.PORT || 3006;
const app = express();
const server = app.listen(port, () => {
console.log(`App started on port ${port}`)
});
const io = socketio(server, { forceNew: true });
io.on('connect', (socket) => {
// do this
// do that
});
The code above is a skeleton of how express and socket.io are used together. Please modify it as per your needs.
Good luck.

Related

How do i start Socket.IO

I want to add socket.io on the index and it is like this i need to figure out how to do this with this code here and i want to emit the data when a route is called in another file how can i do this? you can see i tried down the code to put the socket io but i don't know can someone help please? also this is made in the backend like this is supposed to be an API and i'll not have a front-end and that's my problem i never used socket.io like this
// all the requires
require('./models/Service');
require('./models/Activities');
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const serviceRoutes = require('./routes/serviceRoutes');
const activityRoutes = require('./routes/activitiesRoutes');
const errorHandler = require('./helpers/Error-handler');
const logger = require('./config/winston');
const http = require('http').Server(app);
// all the app use
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(serviceRoutes);
app.use(activityRoutes);
app.use(errorHandler);
// this calls for the users route to authenticate
app.use('/users', require('./Users/user.controller'));
// connection to database
mongoose.connection.on('connected', () => {
console.log('Connected to mongo instance');
});
mongoose.connection.on('error', err => {
console.error('Error connecting to mongo', err);
});
// server start up
const port = process.env.NODE_ENV === 'production' ? 80 : 4000;
http.listen(port, function() {
console.log('listening on ' + port);
try {
logger.info('Server and Database is initiated');
}
catch (error) {
logger.error(error);
}
});
// implementation of io
const io = require("socket.io")(http);
io.on('connection', function(socket) {
console.log('A user connected');
socket.on('disconnect', function () {
console.log('A user disconnected');
});
});
app.get('/', function(req, res) {
res.send(console.log('hey', io))
});
module.exports = io;
You can have the socket join a room on connection and attach io to the app object with app.set('io', io). This can then be accessed in controllers with req.app.get('io'), and you can emit to specific rooms.

Express server and socket.io not working in same port

Not working can't find any issue in code##
If I put any port number instead of server it's working but why didn't it's working with socket server anyone explain
I tried some solution but none of them work I want to run socket.io and express on same port number
const express = require('express');
const cors = require("cors");
const socketIO = require('socket.io');
const http = require('http');
const app = express();
const server = http.createServer(app);
const passport = require("passport");
const authRoute = require('./routes/auth');
const userRoute = require('./routes/user');
const PORT = process.env.PORT || 9000;
const db = require('./config/mongoose');
app.use(express.json());
app.use(cors());
app.use(passport.initialize());
require("./config/passport")(passport);
app.use(express.json());
app.use("/api/auth", authRoute);
app.use("/api/user", passport.authenticate('jwt', { session: false }),userRoute);
if(process.env.NODE_ENV === 'production')
{
app.use(express.static('client/build'))
}
Here is the issue if I switch server to any port number it's fine
const io = socketIO(server, {
cors: {
origin: '*',
}
});
let state = {};
io.on("connection", (socket) => {
const { id } = socket.client;
socket.on('disconnect', function () {
console.log('socket disconnected!');
});
socket.on('join_room', function (data) {
console.log('joining request rec.', data);
socket.join(data.room);
io.in(data.room).emit('user_joined', data);
});
socket.on('send_code', function (data) {
io.in(data.room).emit('receive_code', data);
});
});
app.listen(PORT, function (err) {
if(err){
console.log(err);
return;
}
console.log(`Server is up and running on port: ${PORT}`);
});
http.createServer(app) and app.listen() are not compatible as they both try to do the same thing. If you look at the source code for app.listen(), you will see this:
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
So, it's creating a DIFFERENT server object. You end up with two and the first one never gets started so when you give it to socket.io, it never works.
Instead, remove this:
const server = http.createServer(app);
And, use this instead:
const server = app.listen(PORT, function (err) { ...});
This way, your server variable will contain the one and only server object that is actually running.
Alternatively, you could remove the app.listen() and then just add this in it's place:
server.listen(PORT, ...);
The general idea is that you want this pair:
const server = http.createServer(app);
server.listen(PORT, ...);
Or, just this:
const server = app.listen(PORT, ...);
You cannot use both. Either way, that server object will represent the server that is actually running and will work with socket.io.

Node.js how to use socket.io in express route

In one of my node.js script i am trying to use socket.io in express route. I found many similar questions and tried to implement the solution as suggested but nothing worked out. May be because of my lack of understanding of express routes. I followed below links,
How use socket.io in express routes with node.js
Use socket.io in expressjs routes instead of in main server.js file
This is my app.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
const PORT = 3000;
server.listen(PORT);
console.log('Server is running');
var api = require('./routes/api');
//app.use('/api', api);
app.use('/api', (req, res) => {
res.sendFile(__dirname + '/api.html');
});
app.get('/', (req, res) => {
res.send("this is home location");
});
And route file api.js in ./routes folder
var express = require('express');
var router = express.Router();
var fs = require("fs");
var bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
console.log("inside api route");
router.get('/', function(req, res, next) {
console.log("api route called");
const connections = [];
var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
io.sockets.on('connection',(socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
socket.emit('server message', jsonobj);
});
//res.send(jsonobj)
});
module.exports = router;
Socket.emit is not showing data on html page i am rendering on route use. My html code is,
//api.html
<!DOCTYPE html>
<html lang="en">
<body>
<div class="container">
<h1 class="jumbotron">
Node js Socket io with socket route example
</h1>
<div class="results">results</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script>
jQuery(document).ready(function() {
var socket = io.connect();
var jsondata = "";
socket.on('server message', function(data){
console.log('got data from server',data)
jsondata = JSON.stringify(data);
//console.log('jsondata',jsondata)
$('.results').html(jsondata);
});
});
</script>
</body>
</html>
Please suggest what i am supposed to get route socket data in html page.
Thanks
Ok, let's try to understand why do you need to send data via the socket inside a route in the first place. Websockets are meant for sending data asynchronously without the client having to make a request. If the client is already making an HTTP request, then you can just send the data in the HTTP response.
Now having said there, there are clearly some use cases where you have to send data to some WebSocket channel based on the actions of some OTHER user's requests. If that is the case, there are multiple ways of doing this. One clean way would be to use an event-driven architecture.
Try something like this... find my comments inline below -
const express = require('express');
const router = express.Router();
const fs = require("fs");
const bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
// move the socket connection outside of the route controller
// you must register the event listeners before anything else
const connections = [];
io.sockets.on('connection', (socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
});
// Event emitter for sending and receving custom events
const EventEmitter = require('events').EventEmitter;
const myEmitter = new EventEmitter();
myEmitter.on('my-event', function (jsonobj) {
// do something here like broadcasting data to everyone
// or you can check the connection with some logic and
// only send to relevant user
connections.forEach(function(socket) {
socket.emit('server message', jsonobj);
});
});
router.get('/some-route', function (req, res, next) {
const jsonobj = [{ name: "john", score: 345 }, { name: "paul", score: 678 }]
// emit your custom event with custom data
myEmitter.emit('my-event', jsonobj);
// send the response to avoid connection timeout
res.send({ok: true});
});
module.exports = router;
At first glance, it looks like you are delcaring the URL prefix twice. Once in app.js and again in api.js.
Try localhost:port/api/api
If this is the case, change
router.get('/api', function(req, res, next){
to
router.get('/', function(req, res, next){
This will allow you to hit localhost:port/api and access your endpoint.
I am just starting to understand this myself, but I think where you are at is close.
In your app.js add to the end of the file:
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
const PORT = 3000;
server.listen(PORT);
console.log('Server is running');
var api = require('./routes/api');
//app.use('/api', api);
app.use('/api', (req, res) => {
res.sendFile(__dirname + '/api.html');
});
app.get('/', (req, res) => {
res.send("this is home location");
});
app.set("socketio", io); // <== this line
That stores the "io" variable in "socketio". Which you can grab in any of your other ".js" files.
var express = require('express');
var router = express.Router();
var fs = require("fs");
var bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
//const io = require('socket.io').listen(server); // <== change this
const io = app.get("socketio"); // <== to this
console.log("inside api route");
router.get('/', function(req, res, next) {
console.log("api route called");
const connections = [];
var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
io.sockets.on('connection',(socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
socket.emit('server message', jsonobj);
});
//res.send(jsonobj)
});
module.exports = router;
And you should do that with any other variables which are required in other ".js" files.
Also note that in your files, you are setting the variables up again. It is better to do the same as I've shown you with "io". The only variable in other files I setup is "app" itself.
Hope this helps...
You tried to create and start the servers from two different places in your single project, which is inconvenient. You just need some cleanup, that's all.
app.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
// Listen to sockets here instead of listening in routes/api.js
const connections = [];
var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
io.sockets.on('connection',(socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
socket.emit('server message', jsonobj);
});
const PORT = 3000;
server.listen(PORT);
console.log('Server is running');
var api = require('./routes/api');
//app.use('/api', api);
app.use('/api', (req, res) => {
res.sendFile(__dirname + '/api.html');
});
app.get('/', (req, res) => {
res.send("this is home location");
});
routes/api.js
var express = require('express');
var router = express.Router();
var fs = require("fs");
var bodyParser = require('body-parser');
// Comment these out
// const app = express();
// const server = require('http').createServer(app);
// const io = require('socket.io').listen(server);
console.log("inside api route");
router.get('/', function(req, res, next) {
console.log("api route called");
// Comment these out
// const connections = [];
// var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
// io.sockets.on('connection',(socket) => {
// connections.push(socket);
// console.log(' %s sockets is connected', connections.length); // this is not printing
// socket.on('disconnect', () => {
// connections.splice(connections.indexOf(socket), 1);
// });
// socket.emit('server message', jsonobj);
// });
//res.send(jsonobj)
});
module.exports = router;
Leave your api.html as it is. Hope this helps.

Cannot start NodeJS Server with Socket.io

So, I have the simple dream to start the Server with Socket.io library, but for some reasons it's does not happen... I cannot understand what is wrong, because I do not gets even the standart message on server run - Server running on port ${port}.
Help, please...
'use strict'
const express = require('express');
const http = require('http');
const io = require('socket.io');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const bcrypt = require('bcrypt-nodejs');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const app = express();
const server = http.Server(app);
const socketServer = io(server);
const router = express.Router();
const chat = require('./routes/chat');
const profile = require('./routes/profile');
const registration = require('./routes/registration');
const login = require('./routes/login');
const logout = require('./routes/logout');
const EmployersSchemaDB = require('./SchemaDB/EmployersSchemaDB');
const MessagesSchemaDB = require('./SchemaDB/MessagesSchemaDB');
const User = require('./SchemaDB/ShemaAuthtificaion');
mongoose.connect('mongodb://test_db');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
res.setHeader('Cache-Control', 'no-cache');
next();
});
app.use(session({
secret: 'work hard',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
router.route('/')
.get((req, res) => {
res.json('Hello on the Homepage!');
});
app.use('/', router);
app.use('/chat', chat);
app.use('/profile', profile);
app.use('/auth/login', login);
app.use('/auth/logout', logout);
app.use('/auth/registration', registration);
const port = process.env.API_PORT || 8989;
socketServer.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Change from this:
socketServer.listen(port, () => {
console.log(`Server running on port ${port}`);
});
to this:
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
You need to start your http server. That's the core server here that works with both Express and socket.io and fields all incoming requests.
Your variable socketServer and your io variable are misnamed (which is probably part of your confusion). socketServer is the actual server, that's the socket.io server-side instance which is typically named io. See the socket.io server doc for details.
You should start with a simpler server:
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const app = express();
const server = http.createServer(app);
const socket = socketio(server);
app.use(express.static(`./public`));
socket.on('connect', socket => {
socket.emit('identify', {'server':'server data'});
});
socket.on('data', data => {
console.log(data);
});
server.listen(4000, () => {
console.log('Server up and running on port 4000');
});
In the front end you can test this like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>test
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script>
<script type="text/javascript">
'use strict';
var socket = io('http://localhost:4000');
socket.on('identify', function (socket) {
console.log(socket);
});
</script>
</body>
</html>

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');
});

Resources