How to get data in one middleware from another? - javascript

I have two middleware functions attached to my app get request which works fine.
const express = require('express');
const app = express();
function fun1 (req, res, next) {
console.log('this is fun1')
next()
}
function fun2 (req, res, next) {
console.log('this is fun2')
next()
}
app.get('/', fun1, fun2, function (req, res, next) {
res.send('User Info')
})
app.listen(8080, () => console.log(`Listening on port 8080!`))
Now if I try to do next('test') in fun1 then it bypass fun2 and does 'test' output in browser window instead of 'User Info' which is correct. But how do I get data in fun2? I need to pass something from fun1 and get it in fun2 for further validation.

Assign it to req. You will have access to the same request and response objects through all middlewares.
Note that next('test') does not respond to the client or at least it is not meant to. It is meant to handle errors. Without an error handler and in development mode, Express shows these errors in the browser.
Read on:
Error handling in Express

You can do this by attaching a key-value pair with req` object.
Now how to do this,
const express = require('express');
const app = express();
function fun1 (req, res, next) {
req.MY_VAR = 'MY_VAL'; // setting the value
console.log('this is fun1')
next()
}
function fun2 (req, res, next) {
let myVar = req.MY_VAR; // retrieving the value
console.log(myVar); // MY_VAL
console.log('this is fun2')
next()
}
app.get('/', fun1, fun2, function (req, res, next) {
res.send('User Info')
})
app.listen(8080, () => console.log(`Listening on port 8080!`))
Now, why not next()? Generally, the value passed in next() will be received by the error argument in app.get('/', function (err, req, res, next) {} );

Related

Express Middlewares execute their arguments, while JavaScript functions doesn't

I want to write an express middleware, I'm calling it express-stack-player.
What this middleware does is that it gives your middlewares access to the objects (req, res, next), by getting the benefit of the JavaScript scopes ex:
The following is a very simplified version of its code, which sums up its core job of it:
const stackPlayer = (stacks) => (req, res, next) => {
// #param stacks: function
const stacksValue = stacks(req, res, next);
for (middleware of stacksValue) {
middleware(req, res, next);
}
};
It used to work during my project which I'm working on until eventually, I discovered an unwanted behaviour by running the following test:
const express = require("express");
const app = express();
const setter = (req, res, next) => {
console.log("hello world");
req.a = {};
req.a.b = 1;
next();
};
const readSomething = (something) => (req, res, next) => {
console.log(something);
};
const stackPlayer = (stacks) => (req, res, next) => {
// #param stacks: function
const stacksValue = stacks(req, res, next);
for (middleware of stacksValue) {
middleware(req, res, next);
}
};
app.get(
"/",
stackPlayer((req, res, next) => [setter, readSomething(req.a.b)])
);
console.clear();
app.listen(4000, () => console.log("listening on port 4000"));
When I run npm start, it prints the following in the terminal just normally:
But when I request GET /, the following error prints out:
I was testing this JavaScript code in the browser to see its behavior:
const obj = {}
const setOnObj = () => {
obj.a = {}, obj.a.b = 1
}
const readSomething = (arg) => {
console.log(arg)
}
setOnObj()
readSomething(obj.a.b)
If you click on Run code snippet, the output will be 1. So why does my express-stack-player package have a different behavior?
By the way, the package is on npm, and it can be downloaded by running
npm i #samislam/switcher
In the past, I made a bigger package called switcher, but now I want to move the core logic of executing the middlewares into a separate package, and I'll call it express-stack-player (if the name would be available by then).

How does a method work as callback in app.use()?

Normally, a function is passed as callback in app.use(), like so:
const express = require('express');
const app = express();
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
In the case of node-expose-sspi however a method is passed:
const express = require('express');
const { sso } = require('node-expose-sspi');
const app = express();
app.use(sso.auth()); //stores something in req.sso
app.use((req, res, next) => {
res.json({
sso: req.sso,
});
});
Why is the method passed with ()? If it uses () why is it no called immediately (without arguments)?
Also, how can I wrap a method in a callback function, e.g.
app.use(myCallback);
function myCallback(req, res, next) {
sso.auth(); //req.sso is undefined
}
app.use(sso.auth());
calls sso.auth() and app.use()s its return value.
You can find over here in the node-expose-sspi source that .auth() indeed returns a new middleware function.
As for the second question
Also, how can I wrap a method in a callback function
you shouldn't do that – Express will call your used middlewares in order; a subsequent callback will have access to whatever a previous middleware has injected into the request.
If you for some reason really need to do that,
const ssoAuth = sso.auth();
function myCallback(req, res, next) {
ssoAuth(req, res, () => {
// whatever would regularly be in `myCallback`
next();
});
}
``

When I chain/nest a middleware, I get an error

I'm trying to run a middleware inside another middleware. When I call the nested middleware, I get an error saying:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Here's my code:
// middleware1
module.exports = function(req, res, next) {
req.user = 'current user';
next();
};
// middleware2
module.exports = function(req, res, next) {
middleware1(req, res, next);
if (req.user !== 'current user') return res.status(403).send('Access denied');
next();
};
// API
router.get('/api', middleware2, async (req, res) => {
return res.send(req.user);
});
What am I doing wrong, and what's the correct way to chain or nest a middleware into another one?
(The web app has more to it, but I only included whatever is necessary to reproduce the error)
Following on #jknotek comments:
Since you are passing the next function from middleware2 to middleware1, you are risking that the final middleware gets called in the part of the call stack, which triggers res.send. Afterwards it proceeds in middleware2, which tries to do a res.status, which will fail.
Either you want to chain middlewares as:
router.get('/api', middleware1, middleware2, [...])
Or you would want your middleware2 to behave somewhat like:
//middleware2
module.exports = function(req, res, next) {
middleware1(req, res, () =>
if (req.user !== 'current user') return res.status(403).send('Access denied');
next();
);
};

express next throwing error as next is not defined

I am trying to pass some predefined functions in the callback of app.post() method. I am getting next is not defined error. Below is my code. Please suggest where I am doing wrong or am I missing any concept here?
var express = require('express');
var app = express()
app.post('/api/signup', function(req, res) {
validateParams(req, res, next),
dbCall(req, res, next),
sendResponse(req, res)
})
where I have each function defined and imported and returning next() after my process.
my validateParams function is below :
validateParams = function(req, res, next) {
console.log("at validator ", req);
next();
}
module.exports = validateParams;
my dbCall function is below :
dbCall = function(req, res, next) {
console.log("at dbCall ", req);
next();
}
module.exports = dbCall;
my sendResponse function is below :
sendResponse = function(req, res) {
console.log("at dbCall ", res);
res.send("Response sent successfully");
}
module.exports = sendResponse;
You probably forgot to add the next argument in your callback.
app.post('/api/signup', function(req, res, next) {
validateParams(req, res, next),
dbCall(req, res, next),
sendResponse(req, res)
})
I think you are trying to use validateParams(req, res, next) and dbCall(req, res, next) as middleware functions. In this case, you need something like this:
const validateParams = (req, res, next) => {
// do stuff here
next();
}
const dbCall = (req, res, next) => {
// do stuff here
next();
}
app.post('/api/signup', validateParams, dbCall, function(req, res) {
sendResponse(req, res)
})
You can read more here

extend expressjs res property

Currenty I am trying to add an error & notice function to my expressjs app. I thought that by calling
app.use(function (req, res, next) {
res.notice = function (msg) {
res.send([Notice] ' + msg);
}
});
the notice function would be attached to all res objects present in my application, enabling me to use it as follows:
app.get('something', function (req, res) {
res.notice('Test');
});
However, the example above does not work. Is there a way to accomplish what I'm trying to do?
You need to call next after adding notice method to res, and you need to add the middleware before routes definition.
var express = require('express');
var app = express();
app.use(function (req, res, next) {
res.notice = function (msg) {
res.send('[Notice] ' + msg);
};
next();
});
app.use(app.router);
app.get('/', function (req, res) {
res.notice('Test');
});
app.listen(3000);

Categories

Resources