This is undefined in NodeJS - node.js

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

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)

Pass object initialized via express middleware to next middleware

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();
// ...
}

Mock method and call through original callback

I have a method that I am trying to test that is invoked through a callback like so:
sessionService.getSession(req, res, req.query.state, handleSessionResponse);
Is there a way, using Sinon, to mock the getSession method and call through to the original callback (handleSessionResponse) in my function? In other words, I do not care about the implementation of getSession but I would like to delegate to the handleSessionResponse anyway to test it.
Here is a sample of the file:
handleSessionResponse(err, data, response) {
// get to this point and make assertions
}
sessionService.getSession(req, res, req.query.state, handleSessionResponse);
Give this a try.
const sinon = require('sinon')
const { mockReq, mockRes } = require('sinon-express-mock')
let request = {
query:{
state:{}
}
}
const req = mockReq(request)
const res = mockRes()
sinon.stub(sessionService, 'getSession').callsFake((req, res, req.query.state, callback) => {
callback(null, {}, {})
});
callback should call your original handleSessionResponse

Mocha, Sinon and Chai testing two http calls inside a callback

I am doing some really simple testing with Chai Mocha and Sinon. I am wondering how you would go about testing a http method that gets called inside of a callback. Please point me in the right direction if you can, struggling to find anything on it, I know you can do it, just not sure how. My code is below:
index.js
const http = require('http')
class Index {
add(a, b) {
return a + b
}
get(uri) {
http.get(uri, () => {
http.get('/', function() {
return
})
})
}
}
module.exports = Index
index.spec.js
const Index = require('../index')
const http = require('http')
const { stub, fake, assert } = require('sinon')
const { expect } = require('chai')
let httpSpy;
beforeEach(function () {
a = new Index()
httpSpy = stub(http, 'get')
})
describe('When the get method is invoked', function () {
beforeEach(function () {
a.get('http://www.google.co.uk')
})
it('should make a call to the http service with passed in uri', function () {
assert.calledOnce(httpSpy) // This really should be called twice (Part I am struggling with)
assert.calledWith(httpSpy, 'http://www.google.co.uk')
// I want to test instead that the httpSpy was called twice as, inside the get method, when the first http get resolves, another one gets fired off also
})
})
There are two issues.
Firstly, we cannot tell when the Index.get() method execution is ended (it does not accept a callback, neither return a promise, not marked as async etc).
get(uri) { ... }
Usage of such method is critically inconvenient. For example: if we'd want to first do Index.get() and then do some action right after we won't be able to.
To fix the this we can just add a callback as a last parameter of Index.get.
The second issue is how the http.get method is stubbed:
httpSpy = stub(http, 'get')
This line basically means: replace http.get with an empty function. That dummy function won't throw if you pass a callback inside but it won't call it.
That is why http.get is called only once. It simply ignores the passed callback where http.get should be called the second time.
To fix this we can use stub.yields() method to make sinon aware that the last parameter passed to a stub is a callback (and sinon needs to call it). You can find the method in the docs.
Here is a working example, please see my comments:
class Index {
// Added a callback here
get(uri, callback) {
http.get(uri, () => {
http.get('/', () => {
// Pass any data you want to return here
callback(null, {});
})
})
}
}
let httpSpy;
beforeEach(() => {
a = new Index()
// Now sinon will expect a callback as a last parameter and will call it
httpSpy = stub(http, 'get').yields();
})
describe('When the get method is invoked', () => {
const uri = 'http://www.google.co.uk';
// Now we are waiting for the execution to end before any assertions
beforeEach(done => {
a.get(uri, done);
});
it('should make a call to the http service with passed in uri', () => {
assert.calledTwice(httpSpy);
assert.match(httpSpy.getCall(0).args[0], uri);
assert.match(httpSpy.getCall(1).args[0], '/');
});
})

Resources