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

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

Related

prevent express middleware from executing for same parent path

This is my code when.
I am hitting put API it is executing middleware 3 times but it should execute for put API only.
app.use('/api/user', MiddlewareFun);
app.get('/api/user', (req, res) => {
//do something
});
app.use('/api/user', MiddlewareFun);
app.post('/api/user', (req, res) => {
//do something
});
app.use('/api/user', MiddlewareFun);
app.put('/api/user', (req, res) => {
//do something
});
please don't say use like this.
app.put('/api/user', MiddlewareFun, (req, res) => {
//do something
});
Well, it's happening, because you've made it to. If you want the middleware, to be executed at only selected method, you have to specify it. For example:
Instead of doing:
app.use('/api/user', MiddlewareFun)
app.put('/api/user', (req, res) => {
//do something
})
replace use method with put. As you'd bind regular route:
app.put('/api/user', MiddlewareFun)
app.put('/api/user', (req, res) => {
//do something
})
Also, one more thing. You don't have to duplicate your middleware call before every route declaration. If you want to apply a middleware to your whole router, you can use .use() (as you did), or .all(); which will result in the same behavior.
The middlewares in Express are binded to app or to router.
The solution to yuur problem is to check the method of the request object at the middleware
let MiddlewareFun = function (req, res, next) {
if (req.method === 'PUT') {
// do something
}
next()
}
app.use('/api/user', MiddlewareFun);
The answer is, You need to write express middleware which is part of your app or router. You can write as many middlewares you want, but in your case you just need it only once and here is the implementation of that.
const MiddlewareFun = function(req, res, next) {
// req is object which consist of information about request made.
// From req object you can get method name which is called.
if(req.method.toLowerString() === 'put') {
// your logic goes here
}
next();
}
app.use('/api/user', MiddlewareFun);
app.get('/api/user', (req, res) => {
//do something
});
app.post('/api/user', (req, res) => {
//do something
});
app.put('/api/user', (req, res) => {
//do something
});

next() omits middleware sub-stack in route.param

In below example for GET /api/users/i request secondMw is never executed even there is a next() call in firstMw. Why is that? How am I supposed to be able to run the secondMw?
var apiRouter = require('express').Router();
apiRouter.param('user', function firstMw(req, res, next, param) {
if(param === 'i'){
return next(); //jump to next mw sub-stack
}
next('route'); //continue with another matching route
}, function secondMw(req, res, next, param) {
console.log('NO, I AM NOT HERE. NEVER');
next();
});
apiRouter.get('/users/:user', function (req, res, next) {
res.json({
id: req.params.user
});
});
app.use('/api', apiRouter);
I don't see that router.params supports middleware stack (compare definition with app.get). But you can use ordered definition for same route.
'use strict';
let express = require('express');
let app = express();
app.use(require('body-parser').urlencoded({extended: false}));
var apiRouter = express.Router();
apiRouter.param('user', function mw1(req, res, next, param) {
console.log('MW1', param);
if (param === 'i')
next();
else
next('Error message'); // better next( new Error('Error message'));
});
apiRouter.param('user', function mw2(req, res, next, param) {
console.log('MW2', param);
next();
})
// If next() have params then Express calls handler error
apiRouter.use(function (err, req, res, next) {
console.log('Error: ', err)
res.send(err.message || err);
});
apiRouter.get('/users/:user', function (req, res, next) {
res.json({id: req.params.user});
});
app.use('/api', apiRouter);
app.listen(3000, function () {
console.log('Listening on port 3000');
});

node-restify parent path handler

If I have two path, let's say /path/one and path/two, and I wan't they both handled by a parent handler first, then handled by their specific handler. How can I achieve it. The code below won't work. Their specific handler never run.
const restify = require('restify');
const app = restify.createServer();
app.get('/path/:type', function (req, res, next) {
console.log(req.params.type + ' handled by parent handler');
next();
});
app.get('/path/one', function (req, res) {
console.log('one handler');
res.end();
});
app.get('/path/two', function (req, res) {
console.log('two handler');
res.end();
});
app.listen(80, function () {
console.log('Server running');
});
Unfortunately this kind of "fall through routing" is not supported in restify. The first route handler that matches the request is executed. But you have some alternatives to implement the given use case
Named next Calls
Instead of calling next() without a parameter you call next(req.params.type) to invoke route one or two. Caveats: In case no route is registered for a type restify will send a 500 response.
const restify = require('restify');
const app = restify.createServer();
app.get('/path/:type', function (req, res, next) {
console.log(req.params.type + ' handled by parent handler');
next(req.params.type);
});
app.get({ name: 'one', path: '/path/one' }, function (req, res) {
console.log('one handler');
res.end();
});
app.get({ name: 'two', path: '/path/two' }, function (req, res) {
console.log('two handler');
res.end();
});
app.listen(80, function () {
console.log('Server running');
});
Common handlers (aka Middleware in express)
Since restify has no mounting feature like express does we need to extract the type param from the current route manually:
const restify = require('restify');
const app = restify.createServer();
app.use(function (req, res, next) {
if (req.method == 'GET' && req.route && req.route.path.indexOf('/path') == 0) {
var type = req.route.path.split('/')[2];
console.log(type + ' handled by parent handler');
}
next();
});
app.get('/path/one', function (req, res) {
console.log('one handler');
res.end();
});
app.get('/path/two', function (req, res) {
console.log('two handler');
res.end();
});
app.listen(80, function () {
console.log('Server running');
});

how to group api in express

Here is the example:
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
//code
});
app.post('/user/register', function(req, res) {
//code
})
app.put('/user/register', validateToken, function(req, res) {
//code
})
app.delete('/user/delete', validateToken, function(req, res) {
//code
})
If I have 10 api that need validToken, I should add validToken middleware 10 times, like:
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
....
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
How can I group api by using the same middleware?
Here's how to re-use the same callback function for multiple routes (like middleware):
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
// code
});
app.post('/user/register', function(req, res) {
// code
});
// Be sure to specify the 'next' object when using more than one callback function.
app.put('/user/register', validateToken, function(req, res, next) {
// code
next();
});
app.delete('/user/delete', validateToken, function(req, res, next) {
// code
next();
});
Also, you can replace app.METHOD (e.g. .post, .get, .put, etc.) with app.all and your callback will be executed for any request type.
Just wrong, so do not put into mass participation of the (Google translated from: 刚才看错了,改成这样就不用放进传参了)
var group = {url:true,url:true,url:true};
app.use(function(req,res,next){
if(group[req.url]){
// Do something with request here
next();
} else {
next();
}
})

How to use asynchronous initialization in a Connect middleware?

I wrote a middleware for Connect and Express that requires some heavy lifting in its setup method. Due to the nature of the initialization tasks this stuff is asynchronous, so I have the problem that the middleware shall only be accessible once the initialization has been run.
Currently I have solved it using a callback:
function setupMiddleware(callback) {
doSomeAsyncInitialization(function () {
callback(function (req, res, next) {
// The actual middleware goes here ...
});
});
}
This works, but it's not nice for the caller. Instead of being able to do
app.use(setupMiddleware());
I have to do:
setupMiddleware(functin (middleware) {
app.use(middleware);
});
Now I was thinking whether there is a better approach, e.g. let the middleware initialize in the background and delay all incoming requests until the middleware is ready.
How could I solve this? Any ideas or best practices that I should use here?
I now solved it using an isInitialized variable and delaying the middleware function itself. See the following example:
var connect = require('connect');
var setup = function () {
var isInitialized = false;
setTimeout(function () {
isInitialized = true;
}, 10000);
function run (req, res, next) {
res.write('Foo');
res.end();
}
function delay (req, res, next) {
if (isInitialized) {
return run(req, res, next);
}
setTimeout(function () {
delay(req, res, next);
}, 1000);
}
return function (req, res, next) {
if (req.url === '/foo') {
delay(req, res, next);
return;
}
next();
}
};
var app = connect();
app.use(setup());
app.use(function (req, res) {
res.write('Fertig!');
res.end();
});
var http = require('http');
http.createServer(app).listen(5000);
Please note that this code has not been optimized or refactored in any way, it just is a demonstration that the idea itself works.
Why you don't do like as follows,
doSomeAsyncInitialization(function () {
//After doing all long running init process just configure your express as follows.
app.use(<middlewares>);
app.listen(<portnumder>);
});

Resources