Why do I get a mongoose ValidationError?

263 views Asked by At

I am at a beginner level with the MEAN stack, trying to work on the following tutorial: adrianmejia.com/blog/2014/10/01/creating-a-restful-api-tutorial-with-nodejs-and-mongodb/. I am using Cloud 9 online IDE.

Part of the tutorial involves testing database POST using curl and Postman. I successfully post a GET request, which at this point in the tutorial gives med an empty array.

I use curl -XGET myc9urlhere:8080/todos - with success (getting [])

And try curl -XPOST myc9urlhere:8080/todos -d 'name=Somename&completed=false&note=somenote' - failing

The stacktrace is as follows:

ValidationError: Todo validation failed
    at MongooseError.ValidationError (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/error/validation.js:23:11)
    at model.Document.invalidate (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/document.js:1486:32)
    at model.Document.set (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/document.js:753:10)
    at model._handleIndex (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/document.js:596:14)
    at model.Document.set (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/document.js:556:24)
    at model.Document (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/document.js:68:10)
    at model.Model (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/model.js:47:12)
    at new model (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/model.js:3250:13)
    at /home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/model.js:1864:51
    at /home/ubuntu/workspace/todo-api/node_modules/mongoose/node_modules/async/internal/parallel.js:27:9
    at eachOfArrayLike (/home/ubuntu/workspace/todo-api/node_modules/mongoose/node_modules/async/eachOf.js:57:9)
    at exports.default (/home/ubuntu/workspace/todo-api/node_modules/mongoose/node_modules/async/eachOf.js:9:5)
    at _parallel (/home/ubuntu/workspace/todo-api/node_modules/mongoose/node_modules/async/internal/parallel.js:26:5)
    at parallelLimit (/home/ubuntu/workspace/todo-api/node_modules/mongoose/node_modules/async/parallel.js:85:26)
    at /home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/model.js:1882:5
    at Function.create (/home/ubuntu/workspace/todo-api/node_modules/mongoose/lib/model.js:1852:17)

A small note is that I have also tried this using the Chrome extension Postman. The tutorial says I must use x-www-form-urlencoded which gives the same error returned. See screenshot. And if I turn to the form-data setting instead, I actually succeed in inserting some data into the database, but just bogus stuff. See the second screenshot.

Postman fail

Postman form-data

I have really tried to research myself - maybe this tutorial is not the greatest place to start either :). Below I will include some details on the code.

Thanks a lot for any help solving this.

Identical to the tutorial, I have created a Model for a todo-list item, as shown (Todo.js):

var mongoose = require('mongoose');

var TodoSchema = new mongoose.Schema({
  name: String,
  completed: Boolean,
  note: String
});

module.exports = mongoose.model('Todo', TodoSchema);

Now in my express routing file todos.js I have the following code:

var express = require('express');
var router = express();
//express.Router() was the original here, that failed on router.get
//as router was then undefined for some reason.

var Todo = require('../models/Todo.js');

/* GET /todos listing. */
router.get('/', function(req, res, next) {
  Todo.find(function (err, todos) {
    if (err) return next(err);
    res.json(todos);
  });
});

/* POST /todos */
router.post('/', function(req, res, next) {
  Todo.create(req.body, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });
});

module.exports = router;

Because I do not know exactly what is wrong here I will also post an extract of my app.js showing my database connection

var routes = require('./routes/index');
var users = require('./routes/users');
var todos = require('./routes/todos');

var app = express();

// load mongoose package
var mongoose = require('mongoose');
// Use native Node promises
mongoose.Promise = global.Promise;
// connect to MongoDB
mongoose.connect('mongodb://'+process.env.IP+'/todo-api')
  .then(() =>  console.log('connection succesful'))
  .catch((err) => console.error(err));

app.use('/', routes);
app.use('/users', users);
app.use('/todos', todos);

And the package-json that was generated (I am using Cloud 9 IDE)

{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "ejs": "*",
    "express": "3.2.6",
    "mongoose": "^4.7.6"
  }
}
2

There are 2 answers

1
Vaterrenanburg On

I think the main problem you're encountering here is that all post parameters are strings. This ends up being fine for the name and note fields of you TodoSchema, but will break when it comes to the completed field, since it is boolean. To address this, try converting the string to a boolean before creating the ToDo entry.

/* POST /todos */
router.post('/', function(req, res, next) {
  req.body.completed = (req.body.completed === 'true');
  Todo.create(req.body, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });
});

Also, the reason that the bogus post worked is because you aren't validating your post data. Consider making sure that the post data coming in though your route has all of the required fields, and doesn't contain anything dangerous.

0
ihoudjedje On

Go to the data folder in your directory. Inside it there is a file mongod.lock. Delete it (you wont require root privileges) just use rm mongod.lock. Come back to main directory and enter ./mongod. hope this will solve the problem