I have a rest api resource that accepts a JSON post. Example:
{
"location": {
"coordinates": [
-122.41941550000001,
37.7749295
]
}
The coordinates are then collected from the request by Express:
module.exports.create = function(req, res, next) {
var coordinates = req.body.location.coordinates;
....
These are then submitted to a Mongoose model. I am writing tests against this where the location.coordinates is missing e.g.
{
"foo": {
"bar": [
-122.41941550000001,
37.7749295
]
}
This then fails within the validation section of the Model with :
locationSchema.path('location.coordinates').validate(function(coordinates){
^
TypeError: Cannot call method 'validate' of undefined
So my question is how would I validate that the input is correct? Should this be done in the route before getting to the model, or should it be done in the model? Any examples of how would also be appreciated.
For reference the Mongoose model looks something like:
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.');
My typical approach is to introduce a service layer in between the routes and the model, and that's where the validation happens. Don't think "service" in the "web service" sense; it simply provides an abstraction level around a given domain. This has the following benefits:
Here's a simplified example of what that might look like:
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
}
});
});
I've applied this structure to 3 or 4 different web apps and APIs at this point, and have grown quite fond of it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With