Friday 28 April 2017

I can't use my input of req.params.id into a function present in other file

I am building a REST API which allows us to create users and some coupons for businesses. For keeping things simple I only have defined a few routes. My main file is coupon-api.js. I have defined my routes in this file and the function that are needed to perform in a different file namely coupons.js for coupon functions and users.js for user functions. My schema is defined in two separate files namely coupon.js and user.js.

The below code works perfectly the first time and returns an empty array.

app.get('/coupons' , coupons.getAllCoupons);

Next through this code I am able to create coupons using POSTMAN
app.post('/coupons' , coupons.createCoupon);

Now if I do
app.get('/coupons' , coupons.getAllCoupons);
I am able to get my newly created coupon with an ID defined. The problem I am facing is that when I go to the following address
localhost:3000/coupons/(the id that I got of the new coupon)
it returns 500 internal server error. The main problem is that my ID which should be stored in req.params.id is not accessible in the file which defines all the functions needed to be performed i.e. coupons.js file.

All of my code is defined below. Main file -- coupon-api.js

const express = require('express');
const path = require('path');
const logger = require('morgan');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');

const config = require('./models/config');

const users = require('./controllers/users');
const coupons = require('./controllers/coupons');
var app = express();

mongoose.connect('localhost:5000');

if(app.get('env') === 'development') var dev = true;

// log if in dev mode
if(dev) app.use(logger('dev'));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended : false }));

//====================================
// More Middleware
//====================================

app.param('id' , function(req,res,next,id) {
        if(!id.match(/^[0-9a-fA-F]{24}$/))
                return res.status(400).send("invalid ID"); // using a regular expression to 
                                                           //discard certain input
});

//=====================================
// Routes
//=====================================

app.get('/users' , users.getUsers);
app.get('/users/:id' , users.getUserById);
app.post('/users' , users.createUser);
app.delete('/users/:id' , users.deleteUserById);
app.put('/users/:id' , users.updateUser);

app.get('/coupons' , coupons.getAllCoupons);
app.get('/coupons/:id' , coupons.getCouponById);
app.post('/coupons' , coupons.createCoupon);
app.put('/coupons/:id' , coupons.updateCoupon);
app.delete('/coupons/:id' , coupons.deleteCouponById);

//Handle 404
app.use(function(req,res,next) {
        var err = new Error('Not Found');
        err.status = 404;
        next(err);
});

//our defined error handler just for testing purposes
app.use(function(err,req,res,next) {
        console.log('oops');
        next(err);
});

//development error handler
if(dev) {
        app.use(function(err,req,res,next) {
                console.log(err);
                res.status(err.status || 500).send();
        });
}

//production error handler
app.use(function(err,req,res,next) {
        res.status(err.status || 500).send();
});

var server = app.listen(config.port);
console.log("Listening at http://localhost:%s in %s mode" , server.address().port,app.get('env'));

module.exports =app;

Controller file defining functions of routes: coupons.js

const Coupon = require('../models/schemas/coupon');

module.exports.createCoupon = function(req,res,next) {          
        var newCoupon = new Coupon(req.body);
        newCoupon.save(function(err,coupon) {
                if(err) return next(err);
                return res.status(200).send("OK");
        });
}

module.exports.getAllCoupons = function(req,res,next) {
        Coupon.find({} , function(err , coupons) {
                if(err) return next(err);
                return res.json(coupons);
        });
}

module.exports.getCouponById = function(req,res,next) {
        Coupon.findById(req.params.id , function(err, coupon) {
                if(err) return next(err);
                if(!coupon) return res.status(404).send("No coupon with that ID");
                return  res.json(coupon);
        });
};

module.exports.updateCoupon = function(req,res,next) {
        Coupon.findOneAndUpdate(req.params.id , req.body , {new:true} , function(err , coupon) {
                if(err) return next(err);
                if(!coupon) return res.status(404).send("No coupon with that ID");
                return res.json(coupon);
        });
}

module.exports.deleteCouponById = function(req,res,next) {
        Coupon.findOneAndRemove(req.params.id , function(err,coupon) {
                if(err) return next(err);
                if(!coupon) return res.status(404).send("No coupon with that ID");
                return res.status(200).send("OK");
        });
}

         
module.exports.getActiveCoupons = function(req,res) {
        Coupon.find( {
                $and: [
                        { startDate : { $lt : now } },
                        { approvedDate: { $exists : true } },
                        { $or: [
                                { endDate : { $gt: now } },
                                { endDate : { $exists : false } }
                        
                        ]}
                ]               
        } , function(err,coupons) {
                if(err) return next(err);
                return res.json(coupons);
 
        });
}

module.exports.getUnapprovedCoupons = function(req, res, next) {
        Coupon.find({approvedDate : {$exists : false }}, function(err, coupons) {
                if(err) return next(err)
                return res.json(coupons);
        });
}

module.exports.approveCoupon = function(req, res, next) {
        Coupon.finOneAndUpdate(req.params.id , { approvedDate : new Date() } , {new : true} , function(err, coupon) {
                if(err) return next(err);
                if(!coupon) return res.status(404).send("No coupon with that ID");
                return res.json(coupon);
        });
}

controller file for defining functions of user routes

const User = require('../models/schemas/user');
        
module.exports.createUser = function(req,res) {
        
        var data = {
                firstName : req.body.firstName,
                lastName : req.body.lastName,
                email : req.body.email,
                password : req.body.password,
                createdDate: new Date()
        };
        
        var newUser = new User(data);
        
        //insert or store  user using mongoose  
        newUser.save(function(err,user) {
                return res.send('it worked');
        });
                
}



module.exports.getUsers = function(req, res, next) {
        User.find( {} , function(err , users) {
                if(err) return next(err)
                return res.json(users);         
        });
}


module.exports.getUserById = function(req,res,next) {
        User.findById(req.params.id , function(err , user) {
                if(err) return next(err);       
                if(!user) return res.status(404).send('user not found');
                return res.json(user);
        
        });
}

module.exports.updateUser = function(req,res,next) {
        User.findOneAndUpdate(req.params.id , req.body , { new:true } , function(err, user) {
        if(err) return next(err);
        if(!user) return res.status(404).send("No user with that ID");
        return res.json(user);  
        });     

}

module.exports.deleteUserById = function(req,res,next) {
        User.findOneAndRemove(req.params.id , function(err , user) {
                if(err) 
                        return next(err);
                if(!user) 
                        return res.status(404).send("No user with that ID");
                return res.status(200).send('OK');
        });

}

My schema code for coupons

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

var couponSchema = new Schema({
        name: {type: String, required: true, trim: true},
        url: {type: String, required: true, trim: true},
        companyName: {type: String, required: true, trim: true},
        startDate: {type: Date, default: Date.now, index: true},
        endDate: {type: Date, index: true},
        tags: [Number],
        clicks: {type: [Date], default: []},
        views: {type: [Date], default: []},
        redeemed: {type: [Date], default: []},
        postedBy: Schema.ObjectId, //ref: 'User', required: true},
        approvedDate: Date
    },
    {
        toObject: { getters: true },
        //change name of mongoose default timestamps
        timestamps: {
            createdAt: 'createdDate',
            updatedAt: 'updatedDate'
        }
    }
);

couponSchema.pre('save', function(callback) {
    // ensure url starts with http://, https://, ftp://
    if (this.url && !(/^((https?)|(ftp)):\/\/.+/.test(this.url)))
        this.url = 'http://' + this.url;
    // update startDate on approval
    if (this.isModified('approvedDate') && this.approvedDate > this.startDate)
        this.startDate = this.approvedDate;

    callback();
});

var Coupon = mongoose.model('Coupon', couponSchema);

module.exports = Coupon;

My schema code for Users

const mongoose = require('mongoose');
const Schema = mongoose.Schema;


var userSchema = new Schema({
        firstName: {type: String, trim: true},
        lastName: {type: String, trim: true},
        classYear: Number,
        email: {type: String, unique: true, sparse: true, trim: true},
        phone: {type: String, unique: true, sparse: true},
        phoneProvider: {type: String, trim: true},
        interests: [Number],
        isAdmin: {type: Boolean, index: true},
        isSuperAdmin: {type: Boolean, index: true},
        hash: String,
        companyName: {type: String, trim: true},
        token: String,
    },
    {
        toObject: { getters: true },
        timestamps: {
            createdAt: 'createdDate',
            updatedAt: 'updatedDate'
        },
    }
);

//hooks defined now
// hash if admin, ensure phone and provider if not
userSchema.pre('save', function(callback) {
    if (this.isAdmin || this.isSuperAdmin) {
        if (!this.email)
            return callback(new Error('Missing email'));
        if (!this.hash)
            return callback(new Error('Missing password'));
        if (!this.companyName)
            return callback(new Error('Missing companyName'));
        
        //TODO hash
       }

    else {
        if (!this.phone)
            return callback(new Error('Missing phone'));
        if (!this.phoneProvider)
            return callback(new Error('Missing phoneProvider'));
    }

    // validate phone
    if (this.phone) {
        if (typeof this.phone !== 'string')
            return callback(new Error('Invalid phone'));
        var phone = '';
        for (var i = 0; i < this.phone.length; i++) {
            if (!isNaN(this.phone[i]))
                phone += this.phone[i];
        }
        if (phone.length !== 10)
            return callback(new Error('Invalid phone'));
        this.phone = phone;
    }

    callback();
});

// create full name
userSchema.virtual('name').get(function() {
    var name = "";
    if (this.firstName) {
        name = this.firstName;
        if (this.lastName) name += ' ' + this.lastName;
    } else if (this.lastName) name = this.lastName;
    return name;
});

// methods for validating password
userSchema.methods.comparePassword = function(pw, callback) {
        bcrypt.compare(pw, this.hash, function(err, isMatch) {
                if (err) return callback(err);
                callback(null, isMatch);
        });
};

var User = mongoose.model('User', userSchema);

module.exports = User;


via Anirudh

No comments:

Post a Comment