Pass object initialized via express middleware to next middleware - node.js

Below is my setup, I am trying to pass an object that is initialized in express middleware to a different middleware function. In my router, Invoke helper.getValues() and get an error that I cannot invoke function getValues of undefined
let helper; // no initial value
const getConfig = async () => {
config = await service.getConfig(configName);
helper = new Helper(config); // Helper is correctly initialized here
};
// declare a new express app
let app = express();
app.use(async function (req, res, next) {
try {
await getConfig(); // invoke the code that initializes my helper
next();
} catch (e) {
console.error(e);
}
});
app.use('/path', MyRouter(helper)); // Pass helper to router - it's undefined in router code
My Router Constructor looks like this
function MyRouter(helper) {
...
... const values = helper.getValues();
}
What is the correct way to pass the helper that is created in getConfig to my router?

Pass it via req or res depending on your intent.
If the data relates to the request such as the requesting user's identity, the session attributes, geoIP or parsed request body then attach it to the req object:
If the data relates to response processing such as variables used by templates/views or requested response format then attach it to the res object.
Assuming you want to pass it via req:
req.helper = await getConfig();
Then to use it:
function router (req, res) {
const values = req.helper.getValues();
// ...
}

Related

How to export an async function inside a router in express?

I have the following route in index.js file-
router.post(/login, async (req,res) => {
async function getUser(id, data){
... Some logic
}
})
How can I export this function so that I can import it and call from another file i.e. register.js which has it's own route.?
Tried module.exports = getUser()
But it says it's not defined.
try defining the function outside the router handler function
async function getUser(id, data){
... Some logic
}
router.post(/login, async (req,res) => {
// getUser should be accessible inside here
})
module.exports = getUser
To accommodate your comment/edit where you mentioned that getUser will adapt the incoming res data to be exported, we need to define a state object outside the getUser function. At least from a functional perspective this will work, but I believe there are better ways to tidy this:
let state = {}
async function getUser(id, data){
// Some logic
// use res here by accessing the state object
}
router.post(/login, async (req,res) => {
// getUser should be accessible inside here
state = res;
})
module.exports = getUser

Pass parameter to middleware function and return result

So guys, what I want to accomplish and not manage to get is to write a function that performs a query against database as a middleware, using req and res objects, and also can be used in a socket connection, to pass parameters to it and not use the req and res objects. Also I want it to return the result of the query. I tried using a middleware wrapper
function myFunc(param1, param2){
return (req, res) => {
here query
}}
works when hitting the endpoint with or without args i send, but dosnt work when i call the function from somewhere else
When you call myFunc you get returned a new function. You need to invoke that funcion, something like
myFunc('value1', 'value2')()
This will cause an error since you have no request or response object. These are express objects.
A better way to re-use the database code would be to put it in a function and inject that function to the middlewere.
E.g.
function getArticleById(id) {
return db.query('select * from articles where id = $1', [id])
}
Then create a middlewhere that takes this function in as dependency
function makeMiddlewere (getArticleById) {
return (req, res) => {
return articleById(req.query.id).then(articles => {
res.json(articles)
})
}
}
Then in your code you can do
Normal way
getArticleById(5).then(articles => {
console.log(articles)
})
Create the middlwere an
const express = require('express')
const getArticleById = require('./articlebyid')
const makeMiddlewere = require('./makemiddlewere')
const middlwere = makeMiddlwere(getArticleById)
const app = express.app
app.get('/article', middlewere)

This is undefined in NodeJS

SO here is my route.js file, which handles all the routes.
// Import post controller
const PostController = require('../controllers/post');
// Call post controller for API
router.post('/posts', PostController.create);
And then there is post.js file in controllers, which exports Post class.
const PostModel = require('../models/post');
class Post
{
async create ()
{
response = {};
let posts = await PostModel.find({});
response.additionalInfo = this.getAdditionalInfo();
res.status(200).send({response});
}
getAdditionalInfo ()
{
// returns some data for users and something
}
}
module.exports = new Post();
Now My question is how do i call getAdditionalInfo() from create method? because if i try this.getAdditionalInfo() i get undefined error.
This is how create is being used:
router.post('/posts', PostController.create);
With your
router.post('/posts', PostController.create);
, router.post is accepting a function named create as a callback. This means that when it's invoked, for example, if the internal code for router.post looks something like this:
(url, callback) => {
on(someevent, () => {
callback();
});
}
The calling context is missing. It's not calling PostController.create(), it's just calling someCallbackVariableName(). So, without a calling context, the this inside of create is undefined as a result.
Instead, either pass a function that invokes create with the proper calling context:
router.post('/posts', () => PostController.create());
Or use .bind to explicitly set the calling context to PostController:
router.post('/posts', PostController.create.bind(PostController));

How to test express middleware with event emitters

I'm trying to write a unit test for an express middleware with event emitters using http-proxy, sinon & rewire. The issue I'm running into is when I stub the external module (in this case http-proxy) when it reaches the event.on line it fails because its undefined.
Heres a snippet of source code:
let middleware = function(options) {
proxy.__proto__ = middleware;
proxy.proxy = buildProxy(extend({}, DEFAULT_OPTIONS, options));
_options = options || {};
proxy.proxy.on('error', function(e, req, res) { // <--- Cannot read property of undefined
logger(req, res, e);
});
proxy.proxy.on('proxyRes', function(proxyRes, req, res) {
logger(req, proxyRes);
});
return proxy;
};
// This method is stubbed
let buildProxy = function(options) {
return httpProxy.createProxyServer(options); // http-proxy module
};
Snippet of the test code:
it.only('should call buildProxy and pass along options', () => {
const testOptions = { someOption: true }
let applicationUnderTest = rewire(UNDER_TEST);
let methodUnderTest = applicationUnderTest.__get__('middleware');
let buildProxySpy = sinon.spy();
applicationUnderTest.__set__('buildProxy', buildProxySpy);
methodUnderTest(testOptions)
expect(buildProxySpy.calledOnce).to.be.true;
})
I was looking for suggestions on how to work around this issue.
Test results:
1) Proxy legacy/integration tests should call buildProxy and pass along options:
TypeError: Cannot read property 'on' of undefined
You need to instruct your spy to return something when called. With sinon, this will actually be a stub:
...
let buildProxySpy = sinon.stub();
buildProxySpy.returns({
proxy: { on: sinon.spy() }
});
...
And of course, you'll want to write additional tests that verify the calls to that returned objects methods, and tests to verify the behavior of the methods passed to the spy returned by the stub.

KoaJS middleware and database access

If I had this to show an index for a users model:
app.use(route.get('/user', list));
function *list() {
var res = yield users.find({});
this.body = res;
};
Is it possible to put the database access part into its own middleware and then call next?
How could you pass the resulting list of users down to the next middleware? And somehow pass next through the route?
So the first middleware is any DB access needed, and the second middleware is presentation?
Essentially you attach the information to the request context or the this keyword within the middleware.
I created a screencast on writing middleware that might be helpful:
http://knowthen.com/episode-4-writing-middleware-in-koajs/
Here is an example of how you would pass information to downstream middleware.
let koa = require('koa'),
users = require('./users'),
app = koa();
function *firstMiddleWare (next) {
this.session = {
user: yield users.find({});
}
yield next;
}
function *secondMiddleware (next) {
// this.session.user is available here
yield next;
}
app.use(firstMiddleWare);
app.use(secondMiddleware);
app.use(function *(){
// this.session.user is available here as well
this.body = this.session.user;
});
app.listen(3000);

Resources