Express: How to factor routes callback - javascript

So I have multiple routes like this:
app.get('/user', function(req, res) {
model.find({}, function(err, docs) {
res.send(docs);
});
});
app.get('/user/:id', function(req, res) {
model.findById(req.params.id, function(err, doc) {
res.send(doc);
});
});
multiplied by a lot.
I'd like to know if they would be a way to factor out that callback function like that:
app.get('/user', function(req, res) {
model.find({}, sendInResponse);
});
app.get('/user/:id', function(req, res) {
model.findById(req.params.id, sendInResponse);
});
My problem is the res scope.

I would refactor it like this:
var find = function (queryFn) {
return function (req, res, next) {
var query = queryFn.apply({ req: req, res: res });
model.find(query, function (err, docs) {
res.send(docs);
});
}
};
Now you have generic query middleware which you can use like this:
app.get('/user/:id', find(function () { return { id: this.req.params.id } });
This is just the tip of what's possible and you can even refactor it more. This is a route from an app I created which uses only generic middleware:
app.get('/users/:username',
data.one('user', data_users.byUsername, 'params.username'),
data.many(data_grows.byUserId, 'locals.user.id'),
general.render('grows/index'));

Related

JS, correct syntax from arrow to normal

Im learning and trying to understand javascript, and in a video im following, the dude used this code
app.post('/content/uploads', (req,res) => {
upload(req, res, (err) => {
console.log(req.file);
res.send('testing');
})
});
now im trying to convert it to normal, i understand that app.post('/content/uploads', (req,res) => {
translates to app.post('/content/uploads', function(req, res){
but when i try to do upload(req, res, (err) => {, i cant.
What i tried is
upload(function(req, res, (err)){
but i get an error in
upload(function(req, res, (err)){
^
SyntaxError: Unexpected token '('
what is the correct way to translate it?
My full failed translation looks like this
app.post('/content/uploads', function(req, res){
upload(function(req, res, (err)){
if(err){
res.render('index', {
msg: err
});
} else {
console.log(req.file);
res.send('test');
}
});
});
Thanks
I suggest you spend some time getting comfortable with the arrow syntax, it's not "abnormal".
In any case, you may find this tool useful: https://babeljs.io/en/repl
You can paste code and select only ES2015 on the left (uncheck the others) and see how it translates the code.
For example, it will output:
app.post('/content/uploads', function (req, res) {
upload(req, res, function (err) {
console.log(req.file);
res.send('testing');
});
});
app.post('/content/uploads', function (req,res) {
upload(req, res, function (err) {
console.log(req.file);
res.send('testing');
})
});
upload(req, res, (err)=>{
//TODO
});
The above code is equivalent to:
var someFunc = (err)=>{
//TODO
};
upload(req, res, someFunc);
So, you can write it with function keyword like this:
upload(req, res, function (err) {
//TODO
});

Can a POST request accept two callbacks and can the first pass data to the second?

I have the following .post() request:
const express = require('express');
const router = express.Router();
const search_controller = require('../controllers/searchController');
const result_controller = require('../controllers/resultController');
//Search Routes
router.post('/', search_controller.search_create_post);
module.exports = router;
Could I add a second callback to it so that the first callback is run, then the second callback as such:
router.post('/', search_controller.search_create_post, result_controller.result_create_post)
Would I need a next() somewhere in those create functions? And could I also pass data from the search_create_post callback to the result_create_post callback? I would want to pass in the newly created Search object's id.
My current search_controller.search_create_post function is a such:
exports.search_create_post = (req, res, next) => {
let newSearch = new Search({ search_text: req.body.search_text });
newSearch.save((err, savedSearch) => {
if (err) {
console.log(err);
} else {
res.send(savedSearch);
}
})
};
You might be able to use like this (based on how your functions are written):
// option A
router.post('/', search_controller.search_create_post, result_controller.result_create_post)
// options B
router.post('/', search_controller.search_create_post)
router.post('/', result_controller.result_create_post)
If search needs to pass data to result, you could set req.search_data in search_create_post and then get the value in result_create_post.
Take a look at https://expressjs.com/en/guide/using-middleware.html. There are a few good examples on this page.
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id)
next()
}, function (req, res, next) {
res.send('User Info')
})
// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id)
})
based on your comment below:
You might be able to do this...
exports.search_create_post = (req, res, next) => {
let newSearch = new Search({ search_text: req.body.search_text });
newSearch.save((err, savedSearch) => {
if (err) {
console.log(err);
} else {
req.searchData = savedSearch;
}
next();
})
};

Providing Custom Params In Express Middleware

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)

NodeJS Express - Want to run handler twice on single route

I have a route router.get('/generateDoc', handleRequest); and I want to run this handleRequest twice. Can someone suggest me how to tackle this situation.
Below is my code example.
function handleRequest(req, res, next) {
for (var i = 0; i < 2; i++) {
cacheService.clean();
PdfController.generatePDfs(req, res, next);
}
}
It's an odd thing to require, but you can do it:
function handleRequestInnards(req, res, next) {
cacheService.clean();
PdfController.generatePDfs(req, res, next);
}
function handleRequest(req, res, next) {
handleRequestInnards(req, res, function() {
handleRequestInnards(req, res, next);
});
}
You would have more luck with a library like Bluebird where you can make this a promise and do stuff like:
function handleRequest(req, res, next) {
Promise.all([
handleRequest(req, res),
handleRequest(req, res)
]).asCallback(next);
}
I think you can also just add the middleware twice:
router.get('/generateDoc', handleRequest, handleRequest);

HTTP requests in Express NodeJS

I have the following code from https://github.com/chjj/tty.js/:
this.get("/hola", function(res) {
iniciar();
});
function iniciar() {
self.init();
}
iniciar();
going to localhost:8080/hola, it does not load. localhost:8080 works perfectly. self.init() calls a function that, in turn, calls other functions. The problem seems to be the following called function:
Server.prototype.initMiddleware = function() {
var self = this
, conf = this.conf;
this.use(function(req, res, next) {
var setHeader = res.setHeader;
res.setHeader = function(name) {
switch (name) {
case 'Cache-Control':
case 'Last-Modified':
case 'ETag':
return;
}
return setHeader.apply(res, arguments);
};
next();
});
this.use(function(req, res, next) {
return self._auth(req, res, next);
});
this.use(term.middleware());
this.use(this.app.router);
this.use(express.static(__dirname + '/../static'));
};
According to express.js documentation:
// a middleware sub-stack which prints request info for any type of HTTP request to /user/:id
app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
So, it seems that there are "conflicts" between first app.get and the others app.use or this.use. How can I solve that?
it's because you are not returnig anything and then the browser is polling this until it return something.
this.app.get("/hola", function(req, res) {
res.writeHead(200, {'content-type':'text/html'});
res.end('/*html code here*/');
});

Categories

Resources