I'm trying to do a POST request using express on node.js and mongoose for mongoDB but using Postman to get data gives me this error:
Error at MongooseError.ValidationError
(C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\error\validation.js:22:16)
at model.Document.invalidate
(C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\document.js:1162:32)
at
C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\document.js:1037:16
at validate
(C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\schematype.js:651:7)
at
C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\schematype.js:679:9
at Array.forEach (native) at
SchemaString.SchemaType.doValidate
(C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\schematype.js:656:19)
at
C:\Users\Matteo\Desktop\app1\node_modules\mongoose\lib\document.js:1035:9
at process._tickCallback (node.js:355:11)
I paste here my server.js file
var express = require('express')
var bodyParser = require('body-parser')
var mongoose = require('mongoose');
var app = express()
app.use(bodyParser.json())
mongoose.connect('mongodb://localhost/social', function(){
console.log('mongodb connected')
})
var postSchema = new mongoose.Schema ({
username : { type: String, required: true },
body : { type: String, required: true },
date : { type: Date, required: true, default: Date.now}
})
var Post = mongoose.model('Post', postSchema)
app.get('/api/posts', function(req, res, next){
Post.find(function(err, posts){
if(err) { return next(err) }
res.json(posts)
})
})
app.post('/api/posts', function(req, res, next){
var post = new Post({
username : req.body.username,
body : req.body.body
})
post.save(function(err, post){
if(err){ return next(err) }
res.json(201, post)
})
})
app.listen(3000, function(){
console.log('Server listening on', 3000)
})
Can anyone help me or it is a problem of mongoose?
I got a similar error today, and reading the docs helped me through.
The doc says:
Defining validators on nested objects in mongoose is tricky, because nested objects are not fully fledged paths.
var personSchema = new Schema({
name: {
first: String,
last: String
}
});
A schema like the above will throw similar error like in your question.
The docs points out the workaround:
var nameSchema = new Schema({
first: String,
last: String
});
personSchema = new Schema({
name: {
type: nameSchema,
required: true
}
});
Source: http://mongoosejs.com/docs/validation.html
in Postman, to test HTTP post actions with raw JSON data, need to select the raw option and also set the header parameters( select header parameter in postman and add in key:value feild which is given below ).
Content-Type: application/json
by default, it comes with Content-Type: text/plain which need to replace with Content-Type: application/json
I think it's Mongoose Validation issue, req.body is actually a JSON formatted-data, console.log(req.body.username) returns the username value. To be general, try to use req.body, please make use to fill-out the required fields upon submission.
app.post('/api/posts', function(req, res, next){
var post = new Post(req.body);
post.save(function(err, post){
if(err){ return next(err) }
res.json(post)
})
})
Better to handle MongooseError.ValidationError when a user fails to fill-in required fields. Try to review your Mongoose Model.
Related
This is my database connection:
app.js
const express = require("express");
const app = express();
var { MongoClient } = require("mongodb");
MongoClient.connect("mongodb://localhost:27017", (err, client) => {
if (err) return console.log(err);
db = client.db("MyDb");
app.listen(5000, () => {
console.log("listening on 5000");
});
});
And this is my insert function:
router.post(
"/register",
[
check("email")
.notEmpty()
.withMessage("Email Field is empty"),
check("email")
.isEmail()
.withMessage("Your email is not valid")
],
function(req, res) {
const errors = validationResult(req);
if (errors.length >= 0) {
res.render("register", { errors: errors.errors });
console.log(errors.errors);
return;
}
const { name, email, password } = req.body;
const newUser = new User({
name: name,
email: email,
password: password
});
newUser.save(function(err) {
if (err) throw err;
console.log(true);
});
}
);
And this is my user model:
User.js
const mongoose = require("mongoose");
const UserSchema = mongoose.Schema({
name: { type: String, require: true },
email: { type: String, require: true, unique: true },
password: { type: String, require: true },
created_at: Date,
updated_at: Date
});
const User = mongoose.model("User", UserSchema);
module.exports = User;
There is no error in terminal or browser. When I click the "register" button, the app will freeze and there is no error message at all.
I already tested many tips concerning the database connection but couldn't solve the issue.
I find there are two order of problems in the proposed code, at least as we can read it in your question:
First, I can't find any binding between mongoose and the established mongodb connection
Second, your route handler does not seem to return any status code / content to the
caller
So, for as I see it, you can
change connection setup as follows
mongoose.connect('mongodb://localhost/test', {useNewUrlParser: true})
.then((conn, err) => {
app.listen(5000, () => {
console.log("listening on 5000");
});
});
in order to bind mongoose with MongoDb configuration
retust a status code, e.g. 201, when the new User has been saved:
newUser.save(function(err) {
console.log('Result', err)
if (err) throw err;
console.log(true);
res.send(201)
});
This way I prevent the application hanging up on receiving request...
I hope this can help you!
validationResult() "Extracts the validation errors from a request and makes them available in a Result object." https://express-validator.github.io/docs/validation-result-api.html Therfore, if you don't have any errors this object will contain no errors ( you can check with .isEmpty()), your endpoint doesn't send a response, and leaves the requestor waiting.
Am creating a registration form where user needs to enter details of his emailid(username),password,DOB,Address,phoneno. All fields are mandatory here emailid acts as an username. I have designed my Mongoose Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var User = new Schema({
username: String,
password: String,
phoneno: {
type: Number,
unique: true,
required: true
},
Address : {
type: String,
required: true
},
Dob: {
type: String,
required: true
}
},{
timestamps: true
});
User.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', User);
My user router is given below
var express = require('express');
var UserDetails = express.Router();
var userSchema=require('../models/user');
var passport = require('passport');
const mongoose = require('mongoose');
var Verify = require('./verify');
UserDetails.post('/register', function(req, res, next) {
var newUser = new userSchema({
username : req.body.email,
Dob : req.body.dob,
Address : req.body.address,
phoneno : req.body.phoneno
});
userSchema.register(newUser,req.body.password, function(err, user) {
if (err) {
console.log(err);
return res.status(500).json({err: err});
}
passport.authenticate('local')(req, res, function () {
console.log(req);
console.log(res);
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
This is the json object am sending via PostMan
{"email":"kannaa.in","password": "abcdef","phoneno":96930,"address":"396 SM Road","dob":"14-05-1992"}
But in the console and postman it says bad request if i try to perform the operation.However it stores the value in DB. I couldn't find out the error.
So after no one answered i found out myself what is the error about PassportJS expects the request to contain req.body.username it doesn't matter how many other datas you send it needs req.body.username from the request side. So all i had to change was rather than email i set it as username in postman and it worked like charm.
My postman Data
{"username":"kannaa.in","password": "abcdef","phoneno":96930,"address":"396 SM Road","dob":"14-05-1992"}
I am making an api rest in which I want to make HTTP requests using Postman, specifically I want to perform a search or update a mongodb document, but this must be by an id which is not the doc_id that provides mongo
models Schema
'use strict'
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const infoClientSchema = Schema ({
idusr: String, /*this is require*/
name: String,
phone: Number,
address: String,
riff: String,
state: String,
city: String,
email: {type: String}
})
module.exports = mongoose.model('InfoCli',infoClientSchema)
Controller (This is the get method I know using findById and is working)
'use strict'
const InfoCli = require('../models/infoclient')
function getInfoCli(req, res){
let infocliId = req.params.infocliId
InfoCli.findById(infocliId, (err, infocli) =>{
if (err) return res.status(500).send({message: 'Error making
request: $(err)'})
if (!infocli) return res.status(404).send({message: 'The client does
not exist '})
res.status(200).send({infoclient: infocli})
})
}
Controller (This is the get method which I thought would work using findOne)
function getInfoByUsr(req, res){
let idusr = req.body.idusr
InfoCli.findOne(idusr, (err, infocli) => {
if (err) return res.status(500).send({message: 'Error making
request: $(err)'})
if (!infocli) return res.status(404).send({message: 'The client does
not exist '})
res.status(200).send({infoclient: infocli})
console.log(infocli) /*The console is not showing anything*/
})
}
Controller (This is the put method which I thought would work using findOneAndUpdate)
function updateByUsr(req, res){
let idusr = req.body.idusr
let update = req.body
InfoCli.findOneAndUpdate(idusr, update, (err, infocliUpdate) => {
if (err) return res.status(500).send({message: 'Error making
request: $(err)'})
if (!idusr) return res.status(404).send({message: 'The client does
not exist '})
res.status(200).send({infocliente: infocliUpdate})
})
}
Routes (not 100% sure about this)
const express = require('express')
const InfoCliCtrl = require('../controllers/infoclient')
const api = express.Router()
api.get('/infoclient/:infocliId', InfoCliCtrl.getInfoCli) /*working*/
api.get('/infoclient/:idusr', InfoCliCtrl.getInfoByUsr)
In your app.js/server.js
you should have bodyparser installed
api.get('/infoclient/:infocliId', InfoCliCtrl.getInfoCli)
api.post('/infoclient/:idusr', InfoCliCtrl.updateByUsr)
If you are passing data as URL parameter, like this /infoclient/:infocliId then you can access that using req.params.infocliId
If you are passing using POST body then you can access data using req.body.
In infoClient.js
To fetch user data
exports.getInfoCli = function(req, res, next){
var incomingData = req.params.infocliId;
InfoCli.findOne({idusr: incomingData}, function(err, data){
if(err){
return res.status(500);
} else {
return res.status(200).send({infoclient: data})
}
});
}
Call the above code by
GET - http://localhost:port/infoclient/3874234634 this 3874234634 is your infocliId you need to pass in route
To update user data
exports.updateByUsr = function(req, res, next){
var userId = req.params.idusr;
var updateData = req.body;
InfoCli.findOneAndUpdate({idusr: userId}, updateData, {new: true }, function(err, data){
if(err){
return res.status(500);
} else {
return res.status(200).send(data)
}
});
}
In the update code we have used {new : true} is to return updated document from DB
Call the above code by
POST method - http://localhost:port/infoclient/3874234634 with data in POST body {name: 'pikachu', phone: 12345, ...}
so you read the userid in url parameter using req.params and body data in req.body
I think you simply need to change the line let idusr = req.body.idusr in your getInfoByUsr() function to let idusr = req.params.idusr
http://expressjs.com/en/api.html#req.body
http://expressjs.com/en/api.html#req.params
Also check the syntax of your findOne and findOneAndUpdate query (because idusr is not a Mongo _id but sort of custom String id):
InfoCli.findOne({ idusr: idusr }, (err, infocli) => { ...
InfoCli.findOneAndUpdate({ idusr: idusr }, update, (err, infocliUpdate) => {..
http://mongoosejs.com/docs/api.html#model_Model.findOne
Thank you all, your answers help me to correct many things in the code.
The problem was a horrible mistake in the routes
See how I was using the same path for two requests
api.get('/infoclient/:infocliId', InfoCliCtrl.getInfoCli) /*working*/
api.get('/infoclient/:idusr', InfoCliCtrl.getInfoByUsr)
The problem was that when I used the identifier for idusr it was in conflict with the ObjectId search
Now
api.get('/infoclient/idusr/:idusr', InfoCliCtrl.getInfoByUsr)
This is my server.js. When I run node server.js then use PostMan to post json, it gives me the following error.
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
app.use(bodyParser.json())
app.get('/api/posts', function(req, res) {
res.json([
{
username: '#rodandrew95',
body: 'node rocks!'
}
])
})
app.listen(3000, function() {
console.log('Server listening on', 3000)
})
var Post = require('./models/post')
app.post('/api/posts', function(req, res, next) {
// console.log('post received')
// console.log(req.body.username)
// console.log(req.body.body)
// res.sendStatus(201)
var post = new Post({
username: req.body.username,
body: req.body.body
});
post.save(function (err, post) {
if (err) { return next(err) }
res.sendStatus(201).json(post)
})
})
The error:
(node:6863) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html
ValidationError: Post validation failed
at MongooseError.ValidationError (/Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/error/validation.js:23:11)
at model.Document.invalidate (/Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/document.js:1486:32)
at /Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/document.js:1362:17
at validate (/Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/schematype.js:705:7)
at /Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/schematype.js:742:9
at Array.forEach (native)
at SchemaString.SchemaType.doValidate (/Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/schematype.js:710:19)
at /Users/andrewrodrigues/Desktop/write_modern/ch_1/node_modules/mongoose/lib/document.js:1360:9
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
I'm trying to learn the MEAN stack through "Write Modern Web Apps with the MEAN Stack" but I'm running into issues all the time, even when I follow the code and instructions exactly. Can anyone help understand this error, and possibly recommend some good resources for learning the mean stack?
This error is triggered because you have provided a mongoose validation in
your schema (in /models/post) and that validation is failing.
For instance, if you provided your model like this :
var postSchema = new Schema({
"username": String,
"body": String,
"email": {
type: String,
required: true
}
});
var Post = mongoose.model('Post', postSchema);
This would fail because email required validator is not respected. Find a full list of validators here.
Side note : res.sendStatus(201).json(post) will set the json body and content-type header after sending a response with 201 status. To send both use :
res.status(201).json(post)
I am building my first express.js application and I have run into my first hurdle.
I have a very simple set up.
routes in app.js:
app.get('/', routes.index);
app.get('/users', user.list);
app.get('/products', product.all);
app.post('/products', product.create);
route(controller) in routes/product.js
var Product = require('../models/product.js');
exports.create = function(req, res) {
new Product({ name: req.query.name, description: req.query.description }).save();
};
exports.all = function(req, res) {
Product.find(function(err, threads) {
if (err) {
res.send('There was an error: ' + err)
}
else {
res.send(threads)
}
});
}
Product model in models/product.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var productSchema = new Schema({
name: String,
description: String
});
module.exports = mongoose.model('Product', productSchema);
I have tried sending post requests with both Postman (chrome extension) as well as Curl. I have noticed that both seem to hang after sending the request, as if waiting for a response, i'm no http expert but I assumed a post would not have a response? But perhaps it responds with whether it was successful or not?
my sample requests:
http://0.0.0.0:3000/products?name=Cool, http://0.0.0.0:3000/products?name=Cool%Product&description=Allo%there%Soldier!
After sending the post and then sending a get request to http://0.0.0.0:3000/products I get an array of objects like so:
{
"_id": "52e8fe40b2b3976033ae1095",
"__v": 0
},
{
"_id": "52e8fe81b2b3976033ae1096",
"__v": 0
},
These are equal to the number of post requests I have sent, indicating to me that the server is receiving the post and creating the document/file, but not actually passing the parameters in.
Some help here would be excellent!
EDIT: It seems the code above is fine, I think I may have forgotten to restart my node server after having made some changes (Doh!), the restart fixed the issue
there is something like an http-request lifecycle, and of course an post has a response.
probably something like a 200 if your insert worked and a 404 if not!
you need to send a response in your create method:
exports.create = function(req, res) {
new Product({ name: req.query.name, description: req.query.description }).save();
res.send('saved');
};
Your post needs a response. You could do something like
var newProduct = new Product({ name: req.query.name, description: req.query.description });
newProduct.save(function(err, entry) {
if(err) {
console.log(err);
res.send(500, { error: err.toString()});
}
else {
console.log('New product has been posted.');
res.send(JSON.stringify(entry));
}
});