getting 404 from a route with a param - express 4 - node.js

Im trying to use a param in a route... tried the 4.x docs on express website but no use.. im still getting 404... seems like its not hitting my function..
The other routes to create and list all itens are fine..
var db = require('../db');
var express = require('express');
var mongoose = require( 'mongoose' );
var Users = mongoose.model( 'Users' );
var app = express.Router();
//PARAM
app.param('name', function(req, res, next, name) {
Users.find({name:name}, function(err, docs) {
if (err) {
return next(err);
}
else if (!name) {
return next(new Error('failed to load user'));
}
req.user = docs[0];
next();
});
});
//SHOW
app.get('/users/:name', function(req,res){
res.render('users/profile', {user: req.user});
});
tried a simple version... same 404... (btw the name exist.. it shows on the list item)
//SHOW
app.get('/users/:name', function(req, res, name){
var name = req.param('name');
Users.find({name: name}, function(err, docs) {
req.user = docs[0];
next();
});
res.render('users/profile', {user: req.user});
});

It's because you're using an Express 4 Router like it's an Express 3 app. A Router lets you set up a collection of related routes, like you have done. However, you then must attach the Router to your larger Express server.
var express = require('express');
var app = express();
var router = express.Router();
// attach some things to router
// router.get('/users/:name', ...)
app.use('/foo', router);
Would mount all the paths that router handles under the /foo path, like /foo/users/:name.

Related

cannot read properties of undefined "_id"

So i'm new to node.js and i've been working on a mini project, a student portal and i am stuck showing relevant courses only based on the students department and level.
student.js
var express = require('express');
var router = express.Router();
const {ensureAuthenticated} = require('../config/auth.js');
const {Student}= require('../models/schema.js');
var axios = require('axios');
var controller = require('../controller.js');
router.get('/register-courses',ensureAuthenticated,function(req, res, next) {
axios.get('http://localhost:3000/student/available-courses')
.then(
(response)=>{
console.log(response.data)
res.render('register-courses',{courses:response.data});
})
.catch(err=>{
console.log(err);
})
});
router.get('/available-courses', controller.getCourse);
module.exports = router;
ive narrowed down the problem to the req.user conditions which if i remove it renders all courses
controller.js
var {Course} = require ('./models/schema.js');
var {Student} = require ('./models/schema.js');
exports.getCourse = (req,res) =>{
const user = Student.findById(req.user._id); //problem is i cant access currently logged in user
console.log(user);
Course.find({departmentsOffering:user.department, level:user.level})
.then(items=>{
res.send(items)
})
.catch(
err=>{
console.log(err);
}
)
}
I think it's because you forgot to add the ensureAuthenticated middleware in your route declaration.
The declaration should be
router.get('/available-courses', ensureAuthenticated, controller.getCourse);

Express middlware not called on sub paths

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
// ...
});

NodeJS - Multiple Router files

I have 2 router files. One is for view routing and other for api requests.
I am trying to set the routing using:
var routes = require('./routes/index'); //View Router
var api = require('./routes/api'); //API Router
app.use('/', routes);
app.use('/api', api);
This fails in case of /api requests. If I remove one of the routings, the other works.
I also tried,
routes(app);
api(app);
But this fails too. Any idea what might be the issue? Please let me know in case additional details are required.
routers/index.js
var express = require('express');
var router = express.Router();
var Promise = require('bluebird');
var nforce = require('nforce');
var org = require('../lib/connection');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'App' });
});
router.get('/accounts', function(req, res, next){
console.log(org);
res.render('partials/' + name);
org.query({query: 'Select Id, Name, Type, Industry, Rating From Account Order By LastModifiedDate DESC'})
.then(function(results){
console.log(results);
res.render('accounts', {title: 'Accounts', records: results.records});
});
});
router.get('/partials/:name', function(req, res, next){
var name = req.params.name;
console.log(name);
res.render('partials/' + name);
});
router.get('/api/:name', function(req, res, next){
var name = req.params.name;
console.log(name);
res.render('api/' + name);
});
module.exports = router;
/routers/api.js
var express = require('express');
var router = express.Router();
var Promise = require('bluebird');
var nforce = require('nforce');
var org = require('../lib/connection');
/* GET home page. */
router.get('/getAccounts', function(req, res, next) {
console.log('in API router...');
org.query({query: 'Select Id, Name, Type, Industry, Rating From Account Order By LastModifiedDate DESC'})
.then(function(results){
console.log(results);
res.json({'accounts': results.records});
});
});
module.exports = router;
Maybe wrong but i see problem in this route.
router.get('/api/:name', function(req, res, next){})
It will match /api/cuteName and it also will match /api/getAccounts.
So you need to make routes more clear. I would suggest to change route inside index.js to be all something like /main/.
And all API routes move to api.js.
Hope this helps.

Exporting express params to a global file

I have a list of url params that I'm using with express.
Now I'm trying to put this in an external file so they can be used though-out the whole app, the param works when it's in the file but not when it's external.
I looked though the documentation but it lacks anything about catching all params.
The main app that has many different API routes.
var routeParams = require('./route_params.js');
app.param(routeParams);
The params file that needs to be used globally though-out the app.
var express = require('express');
var router = express.Router();
require('./models/User');
var mongoose = require('mongoose');
var User = mongoose.model('User');
//UserId param.
router.param('userid', function(req, res, next, id)
{
var query = User.findById(id);
query.exec(function (err, user)
{
if(err)
{
res.json(err);
}
else if(!user)
{
res.json({message:'User does not exist'});
}
else
{
req.userid = user;
return next();
}
});
});
module.exports = router;

How to separate the routes and models from app.js using NodeJS and Express

I'm creating an app using Node and Express. However, I can see it'll soon become difficult to manage all the routes that are placed inside app.js. I have placed all my models in a subdirectory /models.
Here's my app current structure:
app.js
models
-- products
-- customers
-- ...
public
views
node_modules
In app.js:
var express = require('express'),
routes = require('./routes'),
user = require('./routes/user'),
http = require('http'),
path = require('path'),
EmployeeProvider = require('./models/employeeprovider').EmployeeProvider,
Products = require('./models/products').Products,
Orders = require('./models/orders').Orders,
Customers = require('./models/customers').Customers,
checkAuth = function(req, res, next) {
if (!req.session.user_id) {
res.send('You are not authorized to view this page');
} else {
next();
}
};
var app = express();
Then some configuration like port, views directory, rendering engine, etc.
Further down app.js I've got the routes:
app.get('/product/edit', auth, function(req, res) {
Products.findAll(function(error, prds) {
res.render('product_edit', {
title: 'New Product',
products: prds
});
});
});
At the top I'm assigning the contents of models/products.js to a variable, all works fine. However keeping all routes inside app.js is not ideal. But if I move the routes to routes/product.js and load the Products models:
var prod = require('../models/products.js');
I get an error saying that object has no method findAll.
What am I doing wrong? How can I remove the routes from app.js?
As of express 4.x Router is added to support your case.
A router object is an isolated instance of middleware and routes. You can think of it as a “mini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.
Example from expressjs site:
// routes/calendarRouter.js
var express = require('express');
var router = express.Router();
// invoked for any requested passed to this router
router.use(function(req, res, next) {
// .. some logic here .. like any other middleware
next();
});
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
// ..
});
module.exports = router;
Then in app.js:
// skipping part that sets up app
var calendarRouter = require('./routes/calendarRouter');
// only requests to /calendar/* will be sent to our "router"
app.use('/calendar', calendarRouter);
// rest of logic
Since I don't like repetition, here's what I do:
// app.js
//...
var routes = requireDir('./routes'); // https://www.npmjs.org/package/require-dir
for (var i in routes) app.use('/', routes[i]);
//...
And each file in routes is like:
// routes/someroute.js
var express = require('express');
var router = express.Router();
router.get('/someroute', function(req, res) {
res.render('someview', {});
});
module.exports = router;
This way you can avoid long repetitive lists like this one:
app.use('/' , require('./routes/index'));
app.use('/repetition' , require('./routes/repetition'));
app.use('/is' , require('./routes/is'));
app.use('/so' , require('./routes/so'));
app.use('/damn' , require('./routes/damn'));
app.use('/boring' , require('./routes/boring'));
Edit: these long examples assume each route file contains something like the following:
var router = express.Router();
router.get('/', function(req, res, next) {
// ...
next();
});
module.exports = router;
All of them could be mounted to "root", but what for them is "root", is actually a specific path given to app.use, because you can mount routes into specific paths (this also supports things like specifying the path with a regex, Express is quite neat in regards to what you can do with routing).
I can suggest you this file structure (according to Modular web applications with Node.js and Express from tjholowaychuk):
app.js
modules
users
index.js
model.js
users-api
index.js
static-pages
index.js
user-api and static-pages export expressjs applications, you can easily mount them in app.js.
In users module you can describe some Data Access operations and all methods about manipulating with the User entity (like create, update etc.). Our API module will use all these methods.
And here is sample code of app.js file (without common express stuff, only mounting routes from different modules):
var express = require('express');
var app = express();
// mount all the applications
app.use('/api/v1', require("user-api"));
app.use(require("static-pages"));
app.listen(3000);
To use your modules this way you must start your app like this NODE_PATH=modules node app.js (i put this line to package.json file in scripts section).
Here is sample code of users module:
index.js
User = require("./model");
module.exports = {
get: function(id, callback) {
User.findOne(id, function(err, user) {
callback(err, user);
});
},
create: function(data, callback) {
// do whatever with incoming data here
data = modifyDataInSomeWay(data);
var newUser = new User(data);
newUser.save(function(err, savedUser) {
// some logic here
callback(err, savedUser);
});
}
};
model.js (with Mongoose stuff for example of course!)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = new Schema({
firstname : {type: String, required: false},
lastname : {type: String, required: false},
email : {type: String, required: true}
});
module.exports = mongoose.model('user', User);
And example of user-api module (here is the main part of the answer about separating routes and models).
var users = require("users");
var express = require("express");
var app = module.exports = express(); // we export new express app here!
app.post('/users', function(req, res, next) {
// try to use high-level calls here
// if you want something complex just create another special module for this
users.create(req.body, function(err, user) {
if(err) return next(err); // do something on error
res.json(user); // return user json if ok
});
});
And example of static-pages. If you are not going to build a kind of REST interface you may simply create several modules that will render pages only.
var express = require("express");
var app = module.exports = express(); // we export new express app here again!
app.get('/', function(req, res, next) {
res.render('index', {user: req.user});
});
app.get('/about', function(req, res, next) {
// get data somewhere and put it in the template
res.render('about', {data: data});
});
Of course you can do whatever you want with modules. The main idea about expressjs is to use a lot of small apps instead of single one.
About nodejs modules you can read stackoverflow and docs.
Hope this helps.

Resources