2014-10-08 49 views
5

我有一个休息api资源,接受一个JSON文章。例如:Node.js,Express,Mongoose - 输入验证 - 在路由或模型中?

{ 
"location": { 
    "coordinates": [ 
     -122.41941550000001, 
     37.7749295 
    ] 
} 

的坐标被从请求快报然后收集:

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

    var coordinates = req.body.location.coordinates; 
    .... 

然后这些提交给猫鼬模型。我正在写这个地方的坐标缺失的测试,例如

locationSchema.path('location.coordinates').validate(function(coordinates){ 
              ^
TypeError: Cannot call method 'validate' of undefined 

所以我的问题是如何将我验证输入的是正确的:

{ 
"foo": { 
    "bar": [ 
     -122.41941550000001, 
     37.7749295 
    ] 
} 

这然后用模型的验证部分中失败了呢?在进入模型之前应该在路线中完成这项工作,还是应该在模型中完成?任何如何的例子也将不胜感激。

仅供参考猫鼬模型看起来像:

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.'); 

回答

6

我的典型方法是在路线和模型之间引入一个服务层,而这也正是验证发生。不要以“网络服务”的意义来考虑“服务”;它只是提供给定域的抽象级别。这有以下好处:

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

下面是什么,可能看起来像一个简单的例子:

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

some-route-file.js

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差异在这一点上不同的网络应用程序和API,并且变得非常喜欢它。

+0

绝对保存作为一个片段! – xShirase 2014-10-08 22:56:47

+0

@ jmar777 - 那很有帮助。介绍该抽象层在我的应用程序中很有意义。感谢您抽出宝贵时间分享您的想法,这对我帮助很大! – Ben 2014-10-08 23:31:19

0

在我看来,验证应首先发生在一开始,在客户端上,然后在路线。

传递无效数据没有多大兴趣,无用资源,所以越早将其标记为无效,越早释放资源。

检查您的坐标的存在,你可以使用:

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

感谢您的意见。那么我将如何验证路线中的输入? – Ben 2014-10-08 22:29:07

+0

你想验证坐标是数字,还是只有'req.body.location.coordinates'存在? – xShirase 2014-10-08 22:33:37

+0

Nooo ...客户端验证与此无关。客户端验证对于用户来说很方便,但是由于用户可以禁用它,所以在安全性方面不提供任何*。 – jmar777 2014-10-08 22:33:44