Why do I get a mongoose ValidationError? - angularjs

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"
}
}

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.

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

Related

Requests API in React-boilerplate

I am using the boilerplate on https://github.com/react-boilerplate/react-boilerplate . The problem is that when I'm hitting API's It's returning error 404. I'm not able to get from where it is setting up the host (which is always going localhost).
no CORS error is also coming up on browser.
Prior to this I was working on create-react-app, there I simple put a "proxy" property in package.json and everything worked fine.
Today I set up this boilerplate for the first time and I would say it's a lil confusing _:)
You can specify API base url like this:
const API = process.env.NODE_ENV !== 'production' ? 'http://google.com' : 'http://localhost:5000'
So in development it will always point to localhost and in production it will point to other your prod server.
For people still searching,
all you need is to create something like this in server/index.js
app.get('/api/user', (req, res, next) => {
let parsedBody = JSON.parse(req.body)
res.send({ express: 'Hello From Express.' });
});
on client side request to /api/user
axios.get(`/api/user`)
.then(function (response) {
console.log("/api/user response", response);
})
.catch(function (error) {
console.log(error);
});
cheers

Receiving "Cannot GET /" error when trying to connect using Node.js/Express

Recently I started trying to get into Node.js/React and am using this tutorial https://auth0.com/blog/build-a-chat-app-with-react/.
However, even though I have followed the steps, I seem to be encountering an error. My page is displayed as "Cannot GET /" after hitting yarn start. I've found answers here NodeJS w/Express Error: Cannot GET /
and here "Cannot GET /" with Connect on Node.js
Neither of these made sense to me though, as my code seems to differ from theirs slightly. I understand that the page doesnt know where to look for my GET request, and therefore what information to pull, but im not sure how to fix it.
The code in question, GET request at the end. Thanks.
// server.js
const express = require('express');
const path = require('path');
const bodyParser = require("body-parser");
const app = express();
const Pusher = require('pusher');
//initialize Pusher with your appId, key and secret
const pusher = new Pusher({
appId: 'APP_ID',
key: 'APP_KEY',
secret: 'SECRET',
cluster: 'YOUR CLUSTER',
encrypted: true
});
// Body parser middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// API route which the chat messages will be sent to
app.post('/message/send', (req, res) => {
// 'private' is prefixed to indicate that this is a private channel
pusher.trigger( 'private-reactchat', 'messages', {
message: req.body.message,
username: req.body.username
});
res.sendStatus(200);
});
// API route used by Pusher as a way of authenticating users
app.post('/pusher/auth', (req, res) => {
const socketId = req.body.socket_id;
const channel = req.body.channel_name;
const auth = pusher.authenticate(socketId, channel);
res.send(auth);
});
// Set port to be used by Node.js
app.set('port', (process.env.PORT || 5000));
app.listen(app.get('port'), function(req, res) {
console.log('Node app is running on port', app.get('port'));
});
I assume that you are sending get request to localhost:5000 which isn't defined in your server so it can't send response back, because you are using react you want to send request on port on which react is running(3000 by default) so try accessing using localhost:3000 and it should work.
You need to have the route available in the code. Try reading up on Express Basic Routing
Try the below and take it from there. I'm assuming that you're running on port 5000, if not, point to whatever port is set in process.env.PORT
app.get('/', function (req, res) {
res.send('hello world');
})

POST request using angular $resource

In my index.js file I have the following POST...
router.route('/bears')
// create a bear (accessed at POST http://localhost:8080/api/bears)
.post(function(req, res) {
var bear = new Bear(); // create a new instance of the Bear model
bear.name = req.body.name; // set the bears name (comes from the request)
// save the bear and check for errors
bear.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Bear created!' });
});
})
.get(function(req, res) {
Bear.find(function(err, bears) {
if (err)
res.send(err);
res.json(bears);
});
});
I test the url http://localhost:8080/api/bears with a POST request on Postman and it was successful. Now I'd like to test my POST request using angular $resource.
I tried the following which I got from the documentation...
app.factory('Profile', function ($resource) {
var Bear = $resource('http://XXX.XXX.X.XX:3000/api/bears/:bearId', {bearId:'#id'});
var single_bear = Bear.post({bearId:123}, function(){
single_bear.name = "Yogi";
single_bear.$save();
});
});
I'm not sure what I should for bearId, I just put a random number. And I am trying to save the bear's name as Yogi. I'm assuming this POST request will occur when I run the app, but I do so and then check to see if my db was filled and there is no entry.
What am I doing wrong?
EDIT
in case you're wondering what a bear entry looks like...
{
"_id": "57ded2302a5ebc050ce3852d",
"__v": 0,
"name": ""
}
Your resource is configured to look for the id property in the data passed (via '#id') yet your data is passing bearId.
Additionally, the data from your server seems to have an _id property, not id nor bearId.
Also, the resource method you're looking for is save(), not post().
I'd go with this type of resource definition...
$resource('http://XXX.XXX.X.XX:3000/api/bears/:id', {id:'#_id'});
Then, you can use it to create a new Bear via
Bear.save({_id: 123, name: 'Yogi'})

Express.js Routes Hang on everything but the homepage

I'm building an app and learning the MEAN stack. I successfully followed a tutorial on thinkster last night and was able to get everything working as expected. Now, however, while trying to do this myself, I'm running into issues. The homepage of my app "burbank" loads fine, but the 3 routes I've created just hang. No errors, nothing in terminal, just try forever to load.
localhost:3000 loads fine
localhost:3000/contacts hangs
index.js
var mongoose = require('mongoose');
var Contact = mongoose.model('Contact');
var Event = mongoose.model('Event');
var Vehicle = mongoose.model('Vehicle');
var express = require('express');
var router = express.Router();
router.get('/contacts', function(req, res, next) {
Contact.find(function(err, contacts){
if(err){ return next(err); }
res.json(contacts);
});
});
router.get('/events', function(req, res, next) {
Event.find(function(err, events){
if(err){ return next(err); }
res.json(events);
});
});
router.get('/vehicles', function(req, res, next) {
Vehicle.find(function(err, vehicles){
if(err){ return next(err); }
res.json(vehicles);
});
});
App.js
var mongoose = require('mongoose');
mongoose.connect = ('mongodb://localhost/burbank');
require('./models/Contacts');
require('./models/Events');
require('./models/Vehicles');
var routes = require('./routes/index');
var users = require('./routes/users');
I originally thought this had to do something with the order that I was placing my requires and variables in app.js, but I don't think that's the case. At any rate, help is much appreciated. I'm slowly grasping all these concepts.
Sometimes all it takes is a weekend away, a hike at the Grand Canyon and 16 hours in the car to find a syntax error.
connect.mongoose = ('mongodb://localhost/burbank');
DOES NOT EQUAL
connect.mongoose('mongodb://localhost/burbank');
To those of you who assisted me, thank you very much. Pardon me while I hang my head in shame.
According to Mongoose docs, the first parameter for find is a dictionary with the filter you want to apply to documents:
http://mongoosejs.com/docs/api.html#model_Model.find
Try something like this:
Contact.find().exec(function(err, contacts) { ...
Try checking to see if the routing works without the mongoose layer using: res.send("example");
When using the .find function in mongoose I believe that you have to pass an empty object as the first parameter (if you want to return the entire collection).
Try changing this:
Contact.find(function(err, contacts){
To this:
Contact.find({}, function(err, contacts){
Repeat that for all of your find queries.

Yeoman Angular-fullstack generator post error

I'm using the Angular-fullstack generator to learn how Angular communicates with Mongoose. After running grunt serve without modifying any files, the Sign up form doesn't work giving a POST 400 (Bad Request).
Where should I do the modifications to get POST create a new user in the database?
An example I uploaded to Openshift.
I had the same problem, this is how I solved:
On file: /lib/controllers/users.js on the create function, change req.body and use req.query instead.
/**
* Create user
*/
exports.create = function (req, res, next) {
var newUser = new User(req.query);
newUser.provider = 'local';
newUser.save(function(err) {
if (err) return res.json(400, err);
req.logIn(newUser, function(err) {
if (err) return next(err);
return res.json(req.user.userInfo);
});
});
};
Regards

Resources