Node.js、Express、Mongoose-输入验证-在路线或模型内?

Node.js、Express、Mongoose-输入验证-在路线或模型内?,node.js,validation,express,mongoose,Node.js,Validation,Express,Mongoose,我有一个接受JSON post的RESTAPI资源。例如: { "location": { "coordinates": [ -122.41941550000001, 37.7749295 ] } 然后通过Express从请求中收集坐标: module.exports.create = function(req, res, next) { var coordinates = req.body.location.coordinates;

我有一个接受JSON post的RESTAPI资源。例如:

{
"location": {
    "coordinates": [
        -122.41941550000001,
        37.7749295
    ]
}
然后通过Express从请求中收集坐标:

module.exports.create = function(req, res, next) {

    var coordinates = req.body.location.coordinates;
    ....
然后将其提交给猫鼬模型。我正在写一个位置坐标缺失的测试

{
"foo": {
    "bar": [
        -122.41941550000001,
        37.7749295
    ]
}
然后在模型的验证部分失败,原因是:

locationSchema.path('location.coordinates').validate(function(coordinates){
                                            ^
TypeError: Cannot call method 'validate' of undefined
所以我的问题是如何验证输入是否正确?这应该在到达模型前的路线中完成,还是应该在模型中完成?如有任何关于如何操作的示例,我们将不胜感激。

作为参考,Mongoose模型如下所示:

var locationSchema = new Schema({
    userid: { type: Number, required: true },
    location: {
        type: [{
            type: "String",
            required: true,
            enum: ['Point', 'LineString', 'Polygon'],
            default: 'Point'
        }], required: true,
        coordinates: { type: [Number], required:true }
    },
    create_date: { type: Date, default: Date.now }
});


locationSchema.path('location.coordinates').validate(function(coordinates){
    ...
}, 'Invalid latitude or longitude.');

在我看来,验证应该在一开始就进行,首先在客户机上进行,然后在路由中进行

人们对传递无效数据、免费使用资源没有多大兴趣,因此越早将其标记为无效,就越早释放资源

要检查坐标是否存在,可以使用:

if(req.body.location.coordinates){
//do your thing
}

我的典型方法是在路由和模型之间引入服务层,这就是进行验证的地方。不要认为“服务”是“web服务”的意思;它只是围绕给定域提供了一个抽象级别。这有以下好处:

  • 它为您提供了处理持久化和/或外部数据的通用抽象。也就是说,无论您是与来自Mongoose的数据交互还是与外部web服务交互,您的所有路由逻辑都可以简单地与一致的接口交互
  • 它围绕持久性细节提供了完善的封装,允许您在不影响所有路由的情况下交换实现
  • 它允许您对非路由使用者(如集成测试套件)重复使用代码
  • 它提供了一个很好的模拟层(例如,用于单元测试)
  • 它提供了一个非常清晰的“验证和业务逻辑在此发生”层,即使您的数据分布在多个不同的数据库和/或后端系统中
下面是一个简化的示例,它可能看起来像什么:

定位服务.js

var locationService = module.exports = {};

locationService.saveCoordinates = function saveCoordinates(coords, cb) {
    if (!isValidCoordinates(coords)) {
        // your failed validation response can be whatever you want, but I
        // like to reserve actual `Error` responses for true runtime errors.
        // the result here should be something your client-side logic can
        // easily consume and display to the user.
        return cb(null, {
            success: false,
            reason: 'validation',
            validationError: { /* something useful to the end user here */ }
        });
    }

    yourLocationModel.save(coords, function(err) {
        if (err) return cb(err);

        cb(null, { success: true });
    });
};
app.post('/coordinates', function(req, res, next) {
    var coordinates = req.body.location.coordinates;

    locationService.saveCoordinates(coordinates, function(err, result) {
        if (err) return next(err);

        if (!result.success) {
            // check result.reason, handle validation logic, etc.
        } else {
            // woohoo, send a 201 or whatever you need to do
        }
    });
});
一些路由文件.js

var locationService = module.exports = {};

locationService.saveCoordinates = function saveCoordinates(coords, cb) {
    if (!isValidCoordinates(coords)) {
        // your failed validation response can be whatever you want, but I
        // like to reserve actual `Error` responses for true runtime errors.
        // the result here should be something your client-side logic can
        // easily consume and display to the user.
        return cb(null, {
            success: false,
            reason: 'validation',
            validationError: { /* something useful to the end user here */ }
        });
    }

    yourLocationModel.save(coords, function(err) {
        if (err) return cb(err);

        cb(null, { success: true });
    });
};
app.post('/coordinates', function(req, res, next) {
    var coordinates = req.body.location.coordinates;

    locationService.saveCoordinates(coordinates, function(err, result) {
        if (err) return next(err);

        if (!result.success) {
            // check result.reason, handle validation logic, etc.
        } else {
            // woohoo, send a 201 or whatever you need to do
        }
    });
});

目前,我已经将此结构应用于3到4个不同的web应用程序和API,并且已经非常喜欢它。

谢谢您的评论。那么,我如何验证路由中的输入?您想验证坐标是否为数字,还是仅验证
req.body.location.coordinates
是否存在?不。。。客户端验证与此无关。客户端验证对于用户来说很方便,但是在安全性方面没有提供任何东西,因为用户可以禁用它。第一层验证可以避免发送半填的表单、不正确的地址等…@xShirase-如果存在的话。一定要将其保存为代码段@jmar777-这非常有用。在我的应用程序中引入抽象层很有意义。谢谢你花时间分享你的想法,这对我帮助很大!