2014-10-08 50 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