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
Related
I have the following code and also have defined the response for POST/messages but when I go to /bc/add and submit a form it shows that Cannot POST /messages.
Can you please explain me the reason?
Here is my code :
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use("/bc/add", (req, res, next) => {
console.log("In the next middleware !", req.url);
res.send(
'<form action="/messages" method="post"><input type="text" name="message"><button type="submit">Submit </button></form>'
);
app.use("/s", (req, res, next) => {
res.send("hup");
});
app.post("/messages", (req, res, next) => {
console.log(req.body);
console.log("In the middleware !", req.url);
res.redirect("/s");
});
});
app.use("/favicon.ico", (req, res, next) => {
console.log("In the middleware !", req.url);
res.sendStatus(204);
});
app.listen(3000, () => {
console.log("Server running at port 3000");
});
You are declaring handlers inside a middleware, which isn't how Express works.
The handlers need to be declared at the "top level":
app.use("/bc/add", (req, res, next) => {
console.log("In the next middleware !", req.url);
res.send(
'<form action="/messages" method="post"><input type="text" name="message"><button type="submit">Submit </button></form>'
);
}); // end of the "middleware"
app.use("/s", (req, res, next) => {
res.send("hup");
});
app.post("/messages", (req, res, next) => {
console.log(req.body);
console.log("In the middleware !", req.url);
res.redirect("/s");
});
Besides that, semantically speaking the handlers for /bc/add/ and /s aren't middleware, but route handlers. It's better to declare them as such explicitely, by using app.get() instead of app.use().
I had originally been using bodyParser as so:
app.use(bodyParser.json());
However, now I want to conditionally use bodyParser:
app.use((req, res, next) => {
if (req.originalUrl === '/hooks') {
next();
} else {
bodyParser.json()(req, res, next);
}
});
When I try to remove (req, res, next), the parser does not work. That is,
app.use((req, res, next) => {
if (req.originalUrl === '/hooks') {
next();
} else {
bodyParser.json();
}
});
does not work.
Why do I need (req, res, next) after bodyParser.json()?
https://github.com/expressjs/body-parser/blob/master/index.js#L108
function bodyParser (options) {
var opts = {}
// exclude type option
if (options) {
for (var prop in options) {
if (prop !== 'type') {
opts[prop] = options[prop]
}
}
}
var _urlencoded = exports.urlencoded(opts)
var _json = exports.json(opts)
return function bodyParser (req, res, next) {
_json(req, res, function (err) {
if (err) return next(err)
_urlencoded(req, res, next)
})
}
}
Body parser is a middleware that needs access to res, req and next.
It parses your request using req and in order to pass control to the next middleware, it needs access to the next function.
Here app.use(bodyParser.json()); are passed (req, res, next) by default as
bodyParser.json() returns return function bodyParser (req, res, next) { .. }
so it becomes --> app.use(function bodyParser (req, res, next) { .. });
but in your case, you are creating a middleware by your self and you are responsible to pass the parameters to bodyParser so it can have access to the required arguments.
app.use((req, res, next) => {
if (req.originalUrl === '/hooks') {
next();
} else {
bodyParser.json()(req, res, next);
}
});
See how app.use works below
https://github.com/expressjs/express/blob/master/lib/application.js#L187-L242
I have an Expressjs route which does a db INSERT (using Sequelize) based on some JSON Body params in the request. The bodyParser middleware does a JSON-schema validation on the body and returns an error if it doesn't validate.
The issue here is that something in bodyparser is executing asynchronously, and I'm getting errors such as null values being inserted into the DB (even after a failed validation), and Headers already returned to client errors.
How to best fix this?
The route:
var bodyParser = json_validator.with_schema('searchterm');
router.post('/', bodyParser, function (req, res, next) {
Searchterm.findOrCreate({
where: {searchstring: req.body.searchstring},
defaults: {funnystory: req.body.funnystory},
attributes: ['id', 'searchstring', 'funnystory']
}).spread((searchterm, created) => {
if (created) {
res.json(searchterm);
} else {
res.sendStatus(409);
}
}).catch(next);
});
The middleware:
var ajv = new Ajv({allErrors: true});
var jsonParser = bodyParser.json({type: '*/json'});
module.exports.with_schema = function(model_name) {
let schemafile = path.join(__dirname, '..', 'models', 'schemas', model_name + '.schema.yaml');
let rawdata = fs.readFileSync(schemafile);
let schema = yaml.safeLoad(rawdata);
var validate = ajv.compile(schema);
return function(req, res, next) {
jsonParser(req, res, next);
if (!validate(req.body)) {
res.status(400).send(JSON.stringify({"errors": validate.errors}));
}
}
};
Your middleware calls next too early; change:
return function(req, res, next) {
jsonParser(req, res, next);
if (!validate(req.body)) {
res.status(400).send(JSON.stringify({"errors": validate.errors}));
}
}
to:
return function(req, res, next) {
if (!validate(req.body)) {
res.status(400).send(JSON.stringify({"errors": validate.errors}));
}
}
and your route definition to:
router.post('/', jsonParser, bodyParser, function (req, res, next) { ... });
I am having a problem with my Node.js app. In short I want to pass custom parameters into my middleware function other than just req, res, and next.
Middleware file:
var DB = require('./DB.js');
function requirePermissions(e) {
console.log('nope')
}
module.exports = requirePermissions;
Route:
router.post('/posts', requirePermissions('post_creation'), function(req, res) {
var o = req.body,
title = o.post.title,
content = o.post.content;
res.send('made it');
});
I have confirmed that using function requirePermissions(req, res, next) {} will work, but I do not understand how to include my own parameters.
Your function requirePermissions should return another function which will be the actual middleware:
function requirePermissions(e) {
if (e === 'post_creation') {
return function(req, res, next) {
// the actual middleware
}
} else if (e === 'something_else') {
return function(req, res, next) {
// do something else
}
}
}
You can also do it like that:
function requirePermissions(e) {
return function(req, res, next) {
if ('session' in req) {
if (e === 'post_creation') {
// do something
} else if (e === 'something_else') {
// do something else
}
}
}
}
You can just create an anonymous function for your middleware that lets you call your actual function with some additional arguments:
router.post('/posts', function(req, res, next) {
requirePermissions('post_creation', req, res, next);
}, function(req, res) {
var o = req.body,
title = o.post.title,
content = o.post.content;
res.send('made it');
});
Or, you can use .bind() to preprend arguments:
router.post('/posts', requirePermissions.bind('post_creation'), function(req, res) {
var o = req.body,
title = o.post.title,
content = o.post.content;
res.send('made it');
});
This will call your requirePermissions() functions with four arguments like this:
requirePermissions('post_creation', req, res, next)
I'm running into a strange issue. The first route is working, but the parameterized route returns a 404 error.
var express = require('express');
var router = express.Router();
router.route('/')
.get(function (req, res, next) {
res.send('A list of vehicles.');
})
.post(function (req, res, next) {
res.send('You added a vehicle!');
});
router.route('/:id')
.get(function (req, res, next, id) {
res.send('Vehicle: ' + id);
})
.put(function (req, res, next, id) {
res.send('You edited vehicle: ' + id);
});
If I add this route:
router.route('/test')
.get(function (req, res, next) {
res.send('This is a test.');
});
...I can hit that endpoint. This also seems to work with another router I'm using, which is using router.get(path, function) and router.post(path, function) instead of the router.route(path).get()... methodology.
Am I missing something obvious here? I'm using Express ~4.12.
Gah, I'm an idiot. Just figured this out. I saw an example that used this function signature:
.get(function (req, res, next, id) {
res.send('Vehicle: ' + id);
})
This apparently doesn't work. I'm not sure if the http methods check the arity of the function, but this did work:
.get(function (req, res, next) {
res.send('Vehicle: ' + req.params.id);
})
I don't remember where I saw that example, but hopefully this helps someone.