Sending a POST request with chai sends an empty body? - javascript

I have the following setup right now
test.js
var user = {
username: 'test_user',
email: 'test#test.me',
password: 'you shall not pass',
address: 'No where street'
};
chai.request(app)
.post('/api/v1/users')
.send(user);
I'm handling the post request in my routes/user.js
router.post('/', function(req, res, next) {
console.log('body: ' + req.body);
queries.insertUser(req.body)
.then(function(id) {
return queries.getSingleUser(id);
})
.then(function(user) {
res.status(200).json(user);
})
.catch(function(err) {
next(err);
});
});
req.body ends up being undefined. Any clue as to what might be going wrong?
The code is live at https://ide.c9.io/burtonium/node-from-scratch if anybody wants to have a look.

req.body being undefined is generally caused by either not using the body-parser middleware in Express, or declaring it incorrectly (for instance, after the route that wants to access req.body).
Assuming that Chai sends JSON, add this to your Express app:
app.use(require('body-parser').json());
(before you declare the routers)

Related

express, mocha testing always returns 404

My express POST route is:
app.post("/addPost", function(req, res) {
let newComment = { post: req.body.createP, comment: req.body.createC };
myDB.push(newComment);
res.render("index.ejs", { posts: myDB });
});
And my mocha test
describe("POST /", function() {
it("it ", function(done) {
supertest(myApp.app)
.post("/")
.expect(200)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
});
Manually, the POST route works fine, but the mocha test always returns 404 instead of 200. Also, the mocha test for GET routes does work. Any ideas whats causing this?
Plus, how would one test html form data being sent via a POST request. Thanks in advance!

req.body returns undefined while using body-parser

I'm trying to build an API that receives a POST req to create a user but I am getting undefined errors for all of my req.body requests. My app is set up like this (simplified for brevity):
User controller that gets called by Express Router in my user routes file
/controllers/user.js
userController.addUser = function(req, res) {
let user = new User();
user.username = req.body.username;
user.first_name = req.body.first_name;
user.last_name = req.body.last_name;
user.email = req.body.email;
user.type = req.body.user_type
// This returns undefined as does all other req.body keys
console.log("REQ.BODY.EMAIL IS: " + req.body.email);
}
User Route File:
/routes/user.js - requires user controller above
router.post('/user/create', userController.addUser);
Main App:
all routes and controllers work per my tests except where req.body.* is used
index.js - main app file
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use('/api', routes);
I have looked through the Express documentation and through countless StackOverflow posts with no luck. Let me know if you need further clarification.
My issue was how I was sending the body to the API endpoint. I was using form-data instead of x-www-form-urlencoded with Postman. User error
Sometime with change in version body-parser seems to not work, in that case just use following, this will remove dependency from body-parser:
router.post('/user/create', (req, res, next) => {
let body = [];
req.on('error', (err) => {
console.error(err);
}).on('data', (chunk) => {
// Data is present in chunks without body-parser
body.push(chunk);
}).on('end', () => {
// Finally concat complete body and will get your input
body = Buffer.concat(body).toString();
console.log(body);
// Set body in req so next function can use
// body-parser is also doing something similar
req.body = body;
next();
});
}, userController.addUser);

Using chai to mock http requests

I'm testing a nodejs app written using express. For the unit testing I'm using chai and sinon. I have the following route in my API that I would like to test.
In my test, I'm simulating the get request with the following code:
chai.request(app)
.get('/downloads')
.send({ wmauth: {
_identity: {
cn: "username",
}
} })
.end((err, res) => {
res.status.should.be.equal(200);
res.body.should.be.a('object');
res.body.should.have.property('Items', []);
AWS.restore('DynamoDB.DocumentClient');
done();
However, I'm always getting the error "Cannot read property '_identity' of undefined". Because the object "wmauth" is not sent in the request, so it is undefined. I have tried to use the send method to try to include it in the request, but no luck. I guess I need to mock it somehow and send it into the request but have no idea how to do it. Could someone help me with this?
Below the method to test:
app.get('/downloads', async (req, res) => {
const created_by_cn = req.wmauth['_identity'].cn;
if(!created_by_cn) {
return res.status(400).json({
error: 'Mandatory parameters: created_by_cn',
});
}
try {
const data = await downloadService.getDownloads(created_by_cn);
return res.status(200).json(data);
}
catch(error){
res.status(500).json({error: error.message});
}
});
THanks
I guess you forgot to use req.body as in:
const created_by_cn = req.body.wmauth['_identity'].cn;
Hope can solve your issue
Since chai-http use superagent, so according to its doc, you need to use query() in order to pass query parameter in get request:
chai.request(app)
.get('/downloads')
.query({ wmauth: {_identity: {cn: "username"}}})
.end((err, res) => { ... });
Then in the express route you can find the parameters in req.query:
app.get('/downloads', function (req, res) {
const created_by_cn = req.query.wmauth._identity.cn;
...
})

How to do whitelist of IP's in Express?

I need to block every IP address from accessing my site except one or two IP's provided by myself. I have tried many modules but nothing seems to work.
var express = require('express')
var AccessControl = require('express-ip-access-control');
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
var middleware = AccessControl(options);
app.use(AccessControl(options));
var options = {
mode: 'deny',
denys: [],
allows: ['**8.1**.1.**'],
forceConnectionAddress: false,
log: function(clientIp, access) {
console.log(clientIp + (access ? ' accessed.' : ' denied.'));
},
statusCode: 401,
redirectTo: '',
message: 'Unauthorized'
};
app.listen(3000, function () {
console.log(' app listening on port 3000!')
})
on running and accessing my site from my above code i am getting the console message as
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
any help?
You can simply add your own middleware that checks the IPs, no need to include another module.
You can see the ip from the request with req.connection.remoteAddress.
Before you define your routes, add something like this:
// Custom Middleware
app.use((req, res, next) => {
let validIps = ['::12', '127.0.0.1']; // Put your IP whitelist in this array
if(validIps.includes(req.connection.remoteAddress)){
// IP is ok, so go on
console.log("IP ok");
next();
}
else{
// Invalid ip
console.log("Bad IP: " + req.connection.remoteAddress);
const err = new Error("Bad IP: " + req.connection.remoteAddress);
next(err);
}
})
This will throw an error if an invalid ip comes in. Below all your routes, add something like this:
// Error handler
app.use((err, req, res, next) => {
console.log('Error handler', err);
res.status(err.status || 500);
res.send("Something broke");
});
You need to define your options before you use them. Otherwise, you're passing in undefined to app.use(AccessControl(options)).
Not sure how this is compiling for you, but adding the following line to the top of your script might help show a few more errors that would help.
'use strict';
Secondly, according to the express-ip-access-control documentation:
'allow' mode (Whilelist):
Deny by default, only allow IPs in the whitelist (allows) and not excluded by the blacklist (denys).
So change options.mode from 'deny' to 'allow'.

Why adding a get parameter forces middleware execution

I have got a middleware like this
// route middleware to verify a token
app.use(function(req, res, next) {
console.log(req.baseUrl);
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({
success: false,
message: 'Failed to authenticate token.'
});
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
This route http://localhost:8080/verifyAccount doesn't responds as No token provided
app.get('/verifyAccount', function (req, res) {
res.json({ message: 'Welcome to verify account!' });
});
But the following route http://localhost:8080/verifyAccount?id=123 does:
app.get('/verifyAccount/:id', function (req, res) {
res.json({ message: 'Welcome to verify account!' });
});
The middleware code is at the bottom in the code file and the get paths are upwards
What is that concept behind?
Why adding a get parameter forces middleware execution?
Just found that if I call it like this http://localhost:8080/verifyAccount/id=123, it properly returns Welcome to verify account!
Found that the issue was in the way by which the route was getting called. Thanks to Thomas Theiner for the help.
The request with query parameter ?id=123 does not match with /:id. It should be called as verifyAccount/123 instead.
Since, the route ?id=123 did not matched any of the path. Hence, was finally reaching the middleware for execution
The position determines the parameter, not the name. The name is only used inside node code to reference the parameter.
For multiple parameters, we'll have multiple slashes like verifyAccount/:id/:otherParameter which would be called using verifyAccount/123/234

Categories