我正在构建一个 REST API ,它允许我们为企业创建用户和一些优惠券。为了简单起见,我只定义了几条路线。 我的主要文件是 coupon-api.js 。我已在此文件中定义了我的路线以及在不同文件中执行所需的功能,即 coupons.js用于优惠券功能,users.js用于用户功能。我的架构在两个单独的文件中定义,即 coupon.js和user.js 。
下面的代码第一次完美运行并返回一个空数组。
app.get('/ coupons',coupons.getAllCoupons);
接下来通过此代码,我可以使用POSTMAN创建优惠券 app.post('/ coupons',coupons.createCoupon);
现在,如果我这样做
app.get('/ coupons',coupons.getAllCoupons);
我可以使用定义的ID获取新创建的优惠券。
我面临的问题是当我去以下地址时
localhost:3000 /优惠券/(我获得新优惠券的身份)
它返回500内部服务器错误。主要问题是应该存储在req.params.id中的我的ID无法在定义所有需要执行的功能的文件中访问,即coupons.js文件。
我的所有代码都在下面定义。 主要文件 - 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;
定义路线功能的控制器文件: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);
});
}
用于定义用户路线功能的控制器文件
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');
});
}
优惠券的架构代码
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;
我的用户架构代码
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;
答案 0 :(得分:0)
我认为问题出在您的中间件app.param()
中。您应该调用next
以使程序流继续到包含名为id
的参数的路由。您可以尝试以下。
app.param('id' , function(req, res, next, id) {
if(!id.match(/^[0-9a-fA-F]{24}$/)){
return res.status(400).send("invalid ID");
} else {
next();
}
});