Catch all errors in Sails while submitting form - node.js

Hey I am new to Sails I am having an issue while submitting form when in my model username and email is set to unique in my input field if I put username and email which already exist in database I am just getting error for unique username not for email if I fix username then I will get error for email but I want both errors to be shown at one go
Here is the model code:
username: {
type: "string",
required: true,
unique: true,
},
name: {
type: "string",
required: true,
},
title: {
type: "string",
},
email: {
type: "string",
isEmail: true,
required: true,
unique: true,
},
password: {
type: "string",
minLength: 6
},
This is controller code
var result=await Users.create(req.allParams(),function(err,data){
if(err)
{
console.log(err);
}
else
{
console.log(data)
}
});```

your controller should be like
module.exports = {
create: async (req, res) => {
//get your params and body using req.params or req.body
try {
//controller's logic here
let user = await Users.create(data).fetch();
res.status(200)
.send({ user })
} catch (error) {
//catch all errors here
res.status(500)
.send({ err:error })
}
},

Related

how to write custom error message in Postman using nodejs

In my case, if I unselect any field in postman, I got an error in the terminal but I want to print that error message or custom error in the postman response. how to do that?
POST method
router.post("/admin/add_profile", upload.single("image"), async (req, res) => {
try {
const send = new SomeModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
phone: req.body.phone,
email: req.body.email,
image: req.file.filename,
});
send.save();
const result = await s3Uploadv2(req.files);
res.json({ status: "Everything worked as expected", result });
} catch (err) {
res.status(404).send(err.message);
}
});
schema.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const SomeModelSchema = new Schema({
first_name: {
type: String,
required: true,
},
last_name: {
type: String,
required: ["last name is required"],
},
phone: {
type: Number,
required: ["Phone number is required"],
unique: true,
validate: {
validator: (val) => {
return val.toString().length >= 10 && val.toString().length <= 12;
},
},
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: ["email address is required"],
validate: (email) => {
return /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
},
match: [
/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/,
"Please fill a valid email address",
],
},
image: {
data: Buffer,
contentType: String
}
});
module.exports = mongoose.model("SomeModel", SomeModelSchema);
here I unselected the first_name field but I got an error in the terminal I want to print that error or a custom error in the postman response.
error message in terminal
You should await the save() call, which returns a Promise.
You should then be able to handle the error in the catch block:
router.post('/admin/add_profile', upload.single('image'), async (req, res) => {
try {
const send = new SomeModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
phone: req.body.phone,
email: req.body.email,
image: req.file.filename,
});
await send.save();
const result = await s3Uploadv2(req.files);
res.json({ status: 'Everything worked as expected', result });
} catch (error) {
if (error.name === "ValidationError") {
let errors = [];
for (const err in error.errors) {
errors.push(err.message)
}
return res.status(400).send(errors);
}
res.status(500).send('Server error');
}
});

Error while trying to save document in MongoDB

I have this signup method to save a user.
exports.signup = function(req, res) {
// Initialize the variables
var user = new User(req.body);
var message = null;
user.provider = 'local';
// save the user
user.save(function(err) {
if (err) {
console.log(err);
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
});
};
Her is my Schema.
var UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
index: true,
match: [/.+\#.+\..+/, "Please fill valid e-mail address"]
},
username: {
type: String,
trim: true,
unique: "Username should be unique",
required: true
},
password: {
type: String,
validate: [
function (password) {
return password && password.length > 6;
},
"Password should be greater than six letters"
]
},
salt: {
type: String
},
provider: {
type: String,
required: "Provider is required"
},
providerId: String,
providerData: {},
created: {
type: Date,
default: Date.now()
}
});
When I make a post request in an empty collection, the first is saved, but after that i am getting this error.
MongoError: Projection cannot have a mix of inclusion and exclusion.
at Function.MongoError.create (/home/sinnedde/WebstormProjects/mean-chatapp/node_modules/mongodb-core/lib/error.js:31:11)
at queryCallback (/home/sinnedde/WebstormProjects/mean-chatapp/node_modules/mongodb-core/lib/cursor.js:212:36)
at /home/sinnedde/WebstormProjects/mean-chatapp/node_modules/mongodb-core/lib/connection/pool.js:455:18
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
POST /signup 500 1445.231 ms - 615
Please help.
First req.body
{
"name":"John",
"email": "johndoe#gmail.com",
"username": "john123",
"password": "password"
}
Second req.body
{
"name":"Jane",
"email": "janedoe#gmail.com",
"username": "jane123",
"password": "password"
}

validation of request parameters in nodejs against database fields

I am building REST API using node, express and MongoDB(using mongoose) i want to add validation to post requests how can I do that I have defined schema like this
var CategorySchema = new Schema({
name: {
type: String,
lowercase: true,
default: '',
trim: true,
unique: [true, 'Category name already exists'],
required: [true, 'Category Name cannot be blank'],
minlength: [4, 'Minimum 4 characters required'],
maxlength: [20, 'Category name cannot be That long']
},
parentCategory: {
type: String,
lowercase: true,
default: '',
trim: true
},
description: {
type: String,
lowercase: true,
default: '',
trim: true,
required: [true, 'description cannot be blank'],
minlength: [10, 'Very short description']
},
slug: {
type: String,
lowercase: true,
unique: [true, 'Slug must be unique'],
required: true,
minlength: [4, "Minimum 4 Charater required"],
maxlength: [20, "Slug cannot be that long"]
},
imageUrl: {
type: String,
default: '',
trim: true
},
created: {
type: Date,
default: Date.now
},
updated: {
type: Date
}
});
module.exports = mongoose.model('Category', CategorySchema);
i am insert data using mongoose models like this
exports.createCategory = function (request, response) {
var newCategory = {
"name": request.body.categoryName,
"parentCategory": request.body.parentCategory,
"description": request.body.description,
"slug": request.body.slug,
"imageUrl": request.body.categoryImage,
"updated": new Date()
}
var category = new Category(newCategory);
category.save()
.then(function (category) {
sendResponse(response, 201, "success", category);
})
.catch(function (error) {
sendResponse(response, 400, "error", error);
});
};
but I want to add validation to the post request. I have to make sure that fields that are defined in a database are there in a request and values must be required as well I am really confused how to validate key in a JSON object inside request body. I have already added some validation using mongoose.
You can use Middlewares for this purpose like (If you are using express framework) :
app.use(function (req, res, next) {
var validationErrors = [];
validationErrors = some_function_to_validate(req); // Returns array
if(validationErrors.length > 0) {
// Send Custom Response with Validation Error
}
else {
next();
}
});
Note : This middleware will be executed for all of your requests (If added before all the routes registration).
For more please refer : http://expressjs.com/en/guide/using-middleware.html
Try following code to get the valid fields. It will return false if any field i.e. not required is coming with the req. Hope this will help.
function validateReq(req)
{
if(req)
{
var prop = ['name','parentCategory','description'] //Add more property name here
var found = false;
for(var key in req.body)
{
if (prop[key] && (prop[key] !== null))
{
found = true;
}
else
{
return false;
}
}
}
else
{
return false;
}
}
exports.createCategory = function (request, response) {
var valid = validateReq(request);
alert(valid);
if(valid){
var newCategory = {
"name": request.body.categoryName,
"parentCategory": request.body.parentCategory,
"description": request.body.description,
"slug": request.body.slug,
"imageUrl": request.body.categoryImage,
"updated": new Date()
}
var category = new Category(newCategory);
category.save()
.then(function (category) {
sendResponse(response, 201, "success", category);
})
.catch(function (error) {
sendResponse(response, 400, "error", error);
});
}
else
{
//Error handling code
}
};
My answer seems to be too late, but hopefully it will help others in future. I think you can try express-validator, here is an article explains how to use it in detail.
Its basic idea is to add a middleware, and put all the validations inside, which can be invoked in subsequent route functions. This way can keep the business logic code clean.
below is an example from official docs
// ...rest of the initial code omitted for simplicity.
const { check, validationResult } = require('express-validator');
app.post('/user', [
// username must be an email
check('username').isEmail(),
// password must be at least 5 chars long
check('password').isLength({ min: 5 })
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
User.create({
username: req.body.username,
password: req.body.password
}).then(user => res.json(user));
});

Model with unique attribute is being created twice

I am using this passport-generate-auth module, and I am trying to get my grasp around understanding this whole thing.
So, in my User model, I've got
var User = {
schema: true,
attributes: {
username: {
type: 'string',
unique: true,
required: true
},
email: {
type: 'email',
unique: true,
required: true
},
password: {
type: 'string',
required: true,
minLength: 8
},
}
};
module.exports = User;
And when I call
exports.register = function (req, res, next) {
var email = req.param('email')
, username = req.param('username')
, password = req.param('password');
User.create({
username: username
, email: email
, password: password
}, function (err, user) {
if (err) {
if (err.code === 'E_VALIDATION') {
if (err.invalidAttributes.email) {
req.flash('error', 'Error.Passport.Email.Exists');
} else {
req.flash('error', 'Error.Passport.User.Exists');
}
}
return next(err);
}
});
};
};
when providing username and email that already exist in the database, the new entry is stored in the DB, instead of giving me an error msg.
Isn't User.create() supposed to take care of checking in the schema attributes rules whether they are unique and then check the records in the DB for a record with a value that already exists?

How to update some but not all fields in Mongoose

here is the UserSchema:
var UserSchema = new Schema({
username: { type: String, required: true, index:{unique: true} },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, index:{unique: true} },
password: { type: String, required: true, select: false }
});
Here is the http PUT request:
// update user information
api.put('/users/:username', function(req, res) {
User.findOne({username: req.params.username}, function(err, user) {
if (err){
res.send(err);
return;
}
if (!user){
res.status(404).send({
success: false,
message: "user not found"
});
} else {
user.username = req.body.username;
user.email = req.body.email;
user.password = req.body.password;
user.firstName = req.body.firstName;
user.lastName = req.body.lastName;
user.save(function(err) {
if (err){
res.send(err);
return;
}
res.json({
success: true,
message: "user information updated."
});
});
}
});
});
The question is, if the user only want to update limited fields, for example, only update username, then the above code does not work, the error looks like this:
{
"message": "User validation failed",
"name": "ValidationError",
"errors": {
"lastName": {
"properties": {
"type": "required",
"message": "Path `{PATH}` is required.",
"path": "lastName"
},
"message": "Path `lastName` is required.",
"name": "ValidatorError",
"kind": "required",
"path": "lastName"
},
"firstName": {
"properties": {
"type": "required",
"message": "Path `{PATH}` is required.",
"path": "firstName"
},
.........
so how can I implemement to allow user updates some but not all fields?
Any comments and suggestions are appreciated!
Using findOneAndUpdate with the operator $set in the update object:
User.findOneAndUpdate({username: req.params.username}, { $set: req.body }, { new: true }, callback);
$set will allow you to modify only the supplied fields in the req.body object.
My solution is:
const dot = require('dot-object'); // this package works like magic
const updateData = { some: true, fields: true };
User.updateOne(
{ _id: req.user._id },
{ $set: dot.dot(updateData) },
(err, results) => {
if (err) res.json({ err: true });
else res.json({ success: true });
}
);
I found this tip (dot package) on: https://github.com/Automattic/mongoose/issues/5285
This is a good compromise:
Specify the fields that the user can update
let fieldToUpdate = {
name: req.body.name,
email: req.body.email,
};
Then delete all the keys that contains falsy value
for (const [key, value] of Object.entries(fieldToUpdate)) {
if (!value) {
delete fieldToUpdate[key];
}
}
Then Update the value using the $set operator
const user = await User.findByIdAndUpdate(
req.user.id,
{ $set: { ...fieldToUpdate } },
{
runValidators: true,
new: true,
}
);
You can use the 'findOneAndUpdate' method.
User.findOneAndUpdate({username: req.params.username}, {username: req.body.username}, function(err, user) {
//...
});
From what I understand is that you want to be able to update any amount of fields. The code below is from a past project.
Model
const ingredientSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type:String, required: true },
quantity: { type: Number, default: 0}
});
HTTP PUT
router.put('/:ingredientId', (req, res, next) => {
// extracting ingredient id from url parameters
const id = req.params.ingredientId;
//creating a map from the passed array
const updateOps = {};
for(const ops of req.body){
updateOps[ops.propName] = ops.value;
}
//updating the found ingredient with the new map
Ingredient.update({_id: id}, { $set: updateOps})
.exec()
.then(result =>{
console.log(result);
//returning successful operation information
res.status(200).json(result);
})
//catching any errors that might have occured from above operation
.catch(err => {
console.log(err);
//returning server error
res.status(500).json({
error: err
});
});
});
PUT Request (json)
[
{"propName": "name", "value": "Some other name"},
{"propName": "quantity", "value": "15"},
]
or if you one want to update one field
[
{"propName": "name", "value": "Some other name"}
]
basically you have an array of these property/field names and their new values. you can update just one or all of them this way if you would like. Or none of them I believe.
Hopefully, this helps! if you have any questions just ask!

Resources