I am trying to read and pass req.params to another middleware. But I am getting an empty object in response.
var app = require('express')();
app.get('/foo/:bar', function(req,res, next) {
console.log('1 --', req.params);
next();
});
app.use(function(req, res, next) {
console.log('2 --', req.params);
res.end();
})
app.listen(3000);
I am hitting this url -
http://localhost:3000/foo/hello
Output I am getting is -
1 -- { bar: 'hello' }
2 -- undefined
How to pass req.params to another middleware?
AFAIK, req.params is only available in handlers that explicitly set a parameter.
So this works:
app.get('/foo/:bar', function(req,res, next) {
console.log('1 --', req.params);
next();
});
app.use('/foo/:bar', function(req, res, next) {
console.log('2 --', req.params);
res.end();
});
If you don't want that, you need to keep a reference to the params in a different property:
app.get('/foo/:bar', function(req,res, next) {
console.log('1 --', req.params);
req.requestParams = req.params;
next();
});
app.use(function(req, res, next) {
console.log('2 --', req.requestParams);
res.end();
});
//route
app.get('/foo/:bar', yourMiddleware, function(req, res) {
res.send('params: ' + req.params);
});
//middleware
function yourMiddleware(req, res, next) {
console.log('params in middleware ' + req.params);
next();
}
Related
I am learning Express.js, MongoDB and Mongoose, and i am creating a small app that lets me store items to a list.
I am trying to Create a GET /list/search route which allows to search for items in the list, but i haven't gotten it to work.
Here is my code
Routes
const express = require('express');
router = express.Router();
const db = require("../models");
router.get('/', function(req, res, next){
db.List.find().then(function(list){
res.render('index', {list});
});
});
router.get('/new', function(req, res, next){
res.render('new');
});
router.get('/:id', function(req, res, next){
db.List.findById(req.params.id).then(function(list){
res.render('show', {list});
});
});
router.get('/:id/edit', function(req, res, next){
db.List.findById(req.params.id).then(function(list){
res.render('edit', {list});
});
});
router.get('/search', function(req, res, next){
db.List.findOne(req.query.search).then(function(list){
console.log(list);
res.render('show', {list});
});
});
router.post('/', function(req, res, next){
db.List.create(req.body).then(function(list){
res.redirect('/');
});
});
router.patch('/:id', function(req, res, next){
db.List.findByIdAndUpdate(req.params.id, req.body).then(function(list){
res.redirect('/');
});
});
router.delete('/:id', function(req, res, next){
db.List.findByIdAndRemove(req.params.id).then(function(list){
res.redirect('/');
});
});
module.exports = router;
Index.pug
extends base.pug
block content
h1 My List
form(action="/list/search" method="GET")
input(type="text" name="search")
input(type="submit", value="search")
a(href="/list/new") Add New Item!
each item in list
p ITEM: #{item.name} QUANTITY: #{item.quantity}
a(href=`/list/${item.id}/edit`) Edit
my main problem is the GET /search, i want to pass in a search query to the search box and return the result to the render file
router.get('/search', function(req, res, next){
db.List.findOne(req.query.search).then(function(list){
console.log(list);
res.render('show', {list});
});
});
Thanks in advance
You need to specify the parameters as attributes in the query. list will be null, if no matching record was found.
router.get('/search', function (req, res, next) {
db.List.findOne({
name: req.query.name,
age: req.query.age
}).then(function (list) {
console.log(list);
if (list === null) {
return res.render('show', {
list: []
});
}
return res.render('show', {
list: list
});
}).catch((err) => {
console.log('err', err);
return res.render('show', {
list: []
});
});
});
In below example for GET /api/users/i request secondMw is never executed even there is a next() call in firstMw. Why is that? How am I supposed to be able to run the secondMw?
var apiRouter = require('express').Router();
apiRouter.param('user', function firstMw(req, res, next, param) {
if(param === 'i'){
return next(); //jump to next mw sub-stack
}
next('route'); //continue with another matching route
}, function secondMw(req, res, next, param) {
console.log('NO, I AM NOT HERE. NEVER');
next();
});
apiRouter.get('/users/:user', function (req, res, next) {
res.json({
id: req.params.user
});
});
app.use('/api', apiRouter);
I don't see that router.params supports middleware stack (compare definition with app.get). But you can use ordered definition for same route.
'use strict';
let express = require('express');
let app = express();
app.use(require('body-parser').urlencoded({extended: false}));
var apiRouter = express.Router();
apiRouter.param('user', function mw1(req, res, next, param) {
console.log('MW1', param);
if (param === 'i')
next();
else
next('Error message'); // better next( new Error('Error message'));
});
apiRouter.param('user', function mw2(req, res, next, param) {
console.log('MW2', param);
next();
})
// If next() have params then Express calls handler error
apiRouter.use(function (err, req, res, next) {
console.log('Error: ', err)
res.send(err.message || err);
});
apiRouter.get('/users/:user', function (req, res, next) {
res.json({id: req.params.user});
});
app.use('/api', apiRouter);
app.listen(3000, function () {
console.log('Listening on port 3000');
});
Here is the example:
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
//code
});
app.post('/user/register', function(req, res) {
//code
})
app.put('/user/register', validateToken, function(req, res) {
//code
})
app.delete('/user/delete', validateToken, function(req, res) {
//code
})
If I have 10 api that need validToken, I should add validToken middleware 10 times, like:
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
....
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
How can I group api by using the same middleware?
Here's how to re-use the same callback function for multiple routes (like middleware):
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
// code
});
app.post('/user/register', function(req, res) {
// code
});
// Be sure to specify the 'next' object when using more than one callback function.
app.put('/user/register', validateToken, function(req, res, next) {
// code
next();
});
app.delete('/user/delete', validateToken, function(req, res, next) {
// code
next();
});
Also, you can replace app.METHOD (e.g. .post, .get, .put, etc.) with app.all and your callback will be executed for any request type.
Just wrong, so do not put into mass participation of the (Google translated from: 刚才看错了,改成这样就不用放进传参了)
var group = {url:true,url:true,url:true};
app.use(function(req,res,next){
if(group[req.url]){
// Do something with request here
next();
} else {
next();
}
})
What should I use:
express.Router().route()
or
express.route()
?
Is it true express.Router().route() is someway deprecated?
For the current version of Express, you should use express.Router().route(). See the express documentation for confirmation. express.Router().route() is not depreciated.
For example:
var router = express.Router();
router.param('user_id', function(req, res, next, id) {
// sample user, would actually fetch from DB, etc...
req.user = {
id: id,
name: 'TJ'
};
next();
});
router.route('/users/:user_id')
.all(function(req, res, next) {
// runs for all HTTP verbs first
// think of it as route specific middleware!
next();
})
.get(function(req, res, next) {
res.json(req.user);
})
.put(function(req, res, next) {
// just an example of maybe updating the user
req.user.name = req.params.name;
// save user ... etc
res.json(req.user);
})
.post(function(req, res, next) {
next(new Error('not implemented'));
})
.delete(function(req, res, next) {
next(new Error('not implemented'));
})
Router.route() can use for chainable routes.
Meaning: You have one API for all the METHODS, you can write that in .route().
var app = express.Router();
app.route('/test')
.get(function (req, res) {
//code
})
.post(function (req, res) {
//code
})
.put(function (req, res) {
//code
})
Is it possible, using Express 4, to send a JSON response to the front-end indicating that there was an error, as well as calling next(err) inside the Express middleware, so that the error can be handled by the server as well? Or are these calls completely mutually exclusive?
My current assumption is that you can do this:
app.get('/', function(req, res, next) {
res.json({ error : true });
});
and you can do this:
app.get('/', function(req, res, next) {
next(new Error('here goes the error message');
});
but that you can't do this
app.get('/', function(req, res, next) {
res.json({ error : true });
next(new Error('here goes the error message');
});
and you can't do this:
app.get('/', function(req, res, next) {
next(new Error('here goes the error message');
res.json({ error : true });
});
They aren't mutually exclusive. For example (instead of middleware I'm using route handlers to demonstrate, but the principle is the same for both):
app.get('/', function(req, res, next) {
res.json({ error : true });
next(new Error('something happened'));
});
app.get('/another', function(req, res, next) {
next(new Error('something happened'));
});
app.use(function(err, req, res, next) {
console.error(err);
if (! res.headersSent) {
res.send(500);
}
});
You could check res.headersSent in the error handler to make sure that a response is sent (if not, the error handler should send one itself).