I am building an API backend with Express (v4) and facing an issue that my middleware function is not called
on sub-paths of my route. E.g. it is called for /movie but not for /movie/search.
I have split my routes into separate files. Below is the code, shortened to the relevant parts.
Any help is appreciated!
app.js
var express = require('express');
var app = express();
var router = require('routes')(app);
/routes/index.js
module.exports = function(app) {
app.use('/movie', check_authentication, require('movie'));
};
/routes/movie.js
var Movie = require(../models/movie');
// Middleware is working for this route (/movie?movie_id=123)
router.get('/', function(req, res) {
Movie.findById(req.query.movie_id)
.then(function(movie) {
res.status(200).json(movie);
}, function(err) {
res.status(400).send(err);
});
});
// Middleware is NOT working for this route (/movie/search?keyword=matrix)
router.get('/search', function(req, res) {
Movie.findById(req.query.keyword)
.then(function(movie) {
res.status(200).json(movie);
}, function(err) {
res.status(400).send(err);
});
});
/routes/check_authentication.js
var express = require('express');
var router = express.Router();
var firebaseAdmin = require('firebase-admin');
var path = require('path');
var config = require(path.resolve(__dirname, '../config/config.json'));
firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(path.resolve(__dirname, '../config/' + config.firebase.serviceAccount)),
databaseURL: config.firebase.databaseURL
});
// AUTHENTICATION MIDDLEWARE
// needs to be included in any request which requires authorization
// =============================================================================
router.all('/', function(req, res, next) {
// check if authorization header is present
var token = req.headers['authorization'];
if (typeof token === 'undefined') {
res.status(403).json({ Error: 'Unauthenticated' });
}
else {
firebaseAdmin.auth().verifyIdToken(token).then(function(decodedToken) {
req.email = decodedToken.email;
next(); // all good. go ahead with the request
}).catch(function(error) {
res.status(403).json({ Error: 'Unauthenticated' });
});
}
});
module.exports = router;
It seems I found the problem.
Changing the middleware to trigger on * fixes it.
router.all('*', function(req, res, next)
Maybe someone can confirm that this is the way to go.
The check_authentication module should export the middleware function, not a router.
module.exports = function(req, res, next) {
// check if authorization header is present
// ...
});
Related
I have got a problem with Express, I am trying to use the app.post() function but it's not working and I don't know why...
Even though I have included the bodyParser()...
It returns 404 page not found error
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var router = express.Router();
router.post("/hello",(req, res) => {
res.send('POST CALL');
});
/* GET home page. */
router.get('/', function(req, res, next) {
MongoClient.connect('mongodb://localhost:27017/nicky', function (err, client) {
if (err) throw err
var db = client.db('nicky')
db.collection('student').find().toArray(function (err, result) {
if (err) throw err
res.send(JSON.stringify(result));
})
})
});
module.exports = router;
GET is working properly, but POST is not.
I am not sure how rest of your code looks, but I have copied your provided snippet and it works this way:
express-post.js:
const express = require('express');
const router = express.Router();
// curl -X POST http://localhost:3000/bar/hello
router.post("/hello",(req, res) => {
res.send('It is POST');
});
// curl -X GET http://localhost:3000/bar/hi
router.get('/hi', function(req, res, next) {
res.send('It is GET');
});
module.exports = router;
express-post-server.js:
const express = require('express');
const bar = require('./express-post');
const app = express();
// curl -X GET http://localhost:3000/foo
app.get('/foo', function (req, res, next) {
res.send('This is foo GET!');
});
// register
app.use('/bar', bar);
app.listen(3000);
For complete running example clone node-cheat and run node express-post.
Maybe you haven't required and initialized body-parser!
Just confirm once if you have included this:
const bodyParser = require('body-parser');
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
May be you forgot to use
app.use('/',require('import route here'));
in main app.
verify_jwt_token
var jwt = require('jsonwebtoken');
var config = require('./env/config.json')
module.exports = function(req,res,next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
console.log("----------------------------------------");
console.log(token);
console.log("----------------------------------------");
console.log(config.jwt_secret);
console.log("----------------------------------------");
// verifies secret and checks exp
jwt.verify(token, config.jwt_secret, function(err, decoded) {
if (err) { //failed verification.
return res.json({"error": true});
}
req.decoded = decoded;
next(); //no error, proceed
});
} else {
// forbidden without token
return res.status(403).send({
"error": true
});
}
}
Routes
var user = require('../controller/user.controller.js');
var token_verify = require('../../config/verify_jwt_token.js')
module.exports = function (app) {
app.route('/register_user').post(user.register);
app.route('/login').get(user.login);
app.route('/auth',token_verify).get(user.auth);
}
I want to call j w t verification function from this route.I don't want to call from the controller. app.route('/auth',token_verify).get(user.auth); Calling from this route
Please help.
Thank you in advance.
This will work-ish:
const express = require('express')
const app = express()
function jwtVerify (req, res, next) {
console.log('verifying token...')
// logic
next()
}
app
.use(jwtVerify)
.route('/example')
.get((req, res) => res.json({ hello: 'World' }))
app.listen(3000)
The issue you will run into is that the middleware will execute for every route you define because the middleware is applied to the app instance. To fix this, you need to make use of the Router. Quick dirty example below:
app.js
const express = require('express')
const app = express()
const securedRoutes = require('./secured-routes')
function jwtVerify (req, res, next) {
console.log('verifying token...')
// logic
next()
}
app.use('/secured', jwtVerify, securedRoutes)
app.listen(3000)
secured-routes.js
const express = require('express')
const router = express.Router()
router.get('/', (req, res) => res.json({ message: 'Hello from secured routes' }))
module.exports = router
How can I convert this express server to using https?
var express = require('express');
var router = express.Router();
var isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
module.exports = function(passport) {
/* GET login page. */
router.get('/', function(req, res) {
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
});
/* GET Registration Page */
router.get('/signup', function(req, res){
res.render('register',{message: req.flash('message')});
});
return router;
}
At the minute you'll probably have something that looks like this:
app.listen(3000);
app.listen is basically an alias for http.createServer(app).listen(3000). Note: This may be in ./bin/www (if you used express-generator).
If you want to have a HTTPS-only server you'll need to replace app.listen or http.createServer() with the following:
var https = require('https');
var fs = require('fs');
// ... Express app
var options = {
key: fs.readFileSync('your/own/key.pem'),
cert: fs.readFileSync('your/own/cert.pem')
};
https.createServer(options, app).listen(8000);
I am getting my hands on node.js and I am trying to understand the whole require/exports thing. I have the following main app.js file:
/app.js
var express = require('express'),
http = require('http'),
redis = require('redis'),
routes = require('./routes'),
var app = express(),
client = redis.createClient();
// some more stuff here...
// and my routes
app.get('/', routes.index);
then, I have the routes file:
exports.index = function(req, res){
res.render('index', { title: 'Express' });
};
I can of course use the client object on my app.js file, but how can I use the same object in my routes?
Since req and res are already being passed around by Express, you can attach client to one or both in a custom middleware:
app.use(function (req, res, next) {
req.client = res.client = client;
next();
});
Note that order does matter with middleware, so this will need to be before app.use(app.router);.
But, then you can access the client within any route handlers:
exports.index = function(req, res){
req.client.get(..., function (err, ...) {
res.render('index', { title: 'Express' });
});
};
The easiest way is to export a function from your routes file that takes a client, and returns an object with your routes:
exports = module.exports = function (client) {
return {
index: function (req, res) {
// use client here, as needed
res.render('index', { title: 'Express' });
}
};
};
Then from app.js:
var client = redis.createClient(),
routes = require('./routes')(client);
I am building a node.js app that will upload files to my S3 bucket using knox. I am able to interact with S3 as expected, but I would like to make my controller to receive configuration so I can dynamically construct my client with configuration values.
My questions is how do I get configuration paramters down the call stack to my controller without being careless?
Disclaimer: I am rather new to Node.js so it could be simply my lack of knowledge in the difference between exports. and module.exports.*
Here is an example of how the interaction works with my code:
app.js
...
config = require('./config/config')['env'];
require('./config/router')(app, config);
...
router.js
module.exports = function(app, config) {
...
var controller = require('../app/controllers/home'); //Is there a way for me to pass config here?
app.post('/upload', controller.upload); //Or here?
...
}
home.js
var knox = require('knox');
var client = knox.createClient({ ... }); //I want to use config.key, config.secret, etc instead of hard-coded values
...
exports.upload = function(req, res) {
//Use client
}
...
Try doing something like this...
var config = require('./config/config')['env'];
// The use function will be called before your
// action, because it is registered first.
app.use(function (req, res, next) {
// Assign the config to the req object
req.config = config;
// Call the next function in the pipeline (your controller actions).
return next();
});
// After app.use you register your controller action
app.post('/upload', controller.upload);
And then in your controller action...
exports.upload = function(req, res) {
//Your config should be here...
console.log(req.config);
}
Ps. I can not try it right now, but I solved a similar issue like this.
You can pass the configuration in as a parameter to you controller
Controller
// controller.js file
module.exports = function(req, res, config) {
console.log('config parameter passed to controller', config);
res.end('config passed')
}
App
// index.js file with the express app
var controller = require('./controller');
var config = {
key1: 'foo'
};
var express = require('express');
var app = express();
var port = 3000;
app.get('/', function(req, res){
controller(req, res, config);
});
app.listen(port);
console.log('app listening on port', 3000);
Demo
You can check out the github repo for a complete example
Alternative approach if you want to call multiple functions from one single route, this will do it.
Route
var users = require('../controllers/users');
app.route('/login').post(function(req, res){
if(users.authenticate()){
console.log('valid user');
if(users.createUser())
{
console.log('user created');
}
}
});
Controller
exports.authenticate = function(req, res, next) {
return true;
};
exports.createUser = function(req, res, next) {
return true;
};