How to show custom express validator error message - node.js

I have used one controller and one model. After post form , i am checking either email id already exist or not. For checking email using express custom validator in controller. Inside controller call model function in which check email using mongodb. But every time condition false. Please guide me , i am new in node js.
enter image description here

Looks like the express-validator already show this as a use case of custom validators:
https://express-validator.github.io/docs/custom-validators-sanitizers.html
const { body } = require('express-validator/check');
app.post('/user', body('email').custom(value => {
return User.findUserByEmail(value).then(user => {
if (user) {
return Promise.reject('E-mail already in use');
}
});
}), (req, res) => {
// Handle the request
});

Related

make a final authentication middleware to return data and validate user?

hello there I'm trying to implement a method to handle returning data in my express project, I want to pass data in all my controllers to a final middleware which its job is to check whether the user has the authority to operate on the document and then return the data ,
req.document = order;
req.validateFields = [
order.senderId._id.toString(),
order.recieverId._id.toString(),
order.driverId._id.toString(),
];
next();
then I handle it in my final middleware like this
app.use(async (req, res, next) => {
const document = req.document;
if (!req.validateFields.includes(req.user._id.toString()))
console.log("not authorized");
await document.save();
res.status(200).json({
document,
});
});
first of all is this a bad practice ? since I save my document after passing the user validations so the data manipulations that have been done in the controllers will not be saved if the user was not authenticated , and then how to handle the other document methods like findByIdandDelete, findByIdAndUpdate which will save the document right away?
thanks.

Mongoose ignore callback on findOne if no result

I'm trying to check if a user is already existing in my DB. For now, I have a very simple controller in express :
app.post('/signup', jsonParser, (req, res) => {
User.findOne(
{ email: req.body.credentials.email },
function (_err, _data) {
res.status(409).send('hello');
}
);
})
If a user indeed exists with the email from the request, a 409 status is sent. But if no user exist matching the email, no response is ever sent. Is this normal behavior ? If yes, how do I callback a function for when I have no result on the findOne ?
Using Mongoose 4.7.7
Problem solved, a schema.post('findOne', function) was defined for the User model and next() was not always called.

Why express validator oneOf is not working as expected

I'm building a project in NodeJS and I'm also using Express. To validate my requests from the client I'm using Express validator and the methods check, oneOf, body, and etc.
I built my PUT endpoint and in parallel also I implemented a validation for the fields to update using oneOf. My goal is that when a client tries to update should at least change one of the fields otherwise a message should come ups informing the client nothing was updated.
My issue is that the PUT updates ignoring my check I implemented and cannot understand the issue as I already did similar before and was working perfectly.
My validator for update looks like:
const updateBookRules = [
oneOf([
check("title")
.exists()
.withMessage("Title is required"),
check("category")
.exists()
.withMessage("Category is required"),
check("price")
.isNumeric()
.withMessage("Price should be a number"),
check("img")
.exists()
.withMessage("Img is required"),
sanitizeBody("price").toFloat()
])
];
In the route, I'm calling this validation as:
// PUT Update a book
router.put("/:asin", check.updateBook, check.rules, async (req, res) => {
// Request ID
const asin = req.params.asin;
// Await the book
await book
// Call model to update the product
.updateBook(asin, req.body)
// Response a message
.then(book =>
res.json({
message: `The book #${asin} has been updated`,
content: book
})
)
// Errors if any
.catch(err => {
if (err.status) {
res.status(err.status).json({ message: err.message });
}
res.status(500).json({ message: err.message });
});
});
The strange is the validation is ignored and I can put also empty strings and no error happens I don't know what is my mistake.
Please comment if you would like to see something more and I will update the question.
Edited Answer
I think I may know the issue. Your code seems fine now that I've had access to the whole repo, but you definitely need to be bringing in validationResult in order to check for validation errors, then stop execution of the router middleware. So, the router.put route-handler would start with:
const { validationResult } = require('express-validator');
// PUT Update a book
router.put("/:asin", check.updateBook, check.rules, async (req, res) => {
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
I'm still not sure about how you setup updateBookRules to use the sanitizeBody() call, and how you have it wrapped in an array. If the above still doesn't work after adding validationResult, try this:
const updateBookRules = oneOf([
check("title")
.exists()
.withMessage("Title is required"),
check("category")
.exists()
.withMessage("Category is required"),
check("price")
.isNumeric()
.withMessage("Price should be a number"),
check("img")
.exists()
.withMessage("Img is required"),
]);
Then make the route-handler signature:
router.put("/:asin", sanitizeBody("price").toFloat(), check.updateBook, check.rules, async (req, res) => {
Also, are you sure there is an error? The docs state that oneOf :
Creates a middleware instance that will ensure at least one of the
given chains passes the validation.
You are checking to make sure that these different fields exist at the PUT route. As long as one of them does exist, check.updateBook will pass. You aren't checking for change here, so the user can simply send you back the same book information, and nothing will fail right?
Per your comments, if you really don't want to use the validationResult you can try to run the validations imperatively, check out the docs

Migrating Node JS code to Apollo server

I am setting up Apollo Server on my Node app and wondered about moving the functionality over to Apollo.
I have business logic like this:
router.post(
'/login',
(req, res, next) => {
if (!req.body.email || !req.body.password) {
return 'You must send the username and the password.';
}
Users.findOne({ email: req.body.email })
.then(user => {
bcrypt.compare(req.body.password, user.password, (err, success) => {
req.user = user;
next();
});
})
},
auth.createToken,
auth.createRefreshToken,
auth.logUserActivity,
(req, res) => {
res.status(201).send({
success: true,
authToken: req.authToken,
refreshToken: req.refreshToken
});
}
);
It follows Node router architecture where I add the found user object to req object, which passes the user to the next functions - createToken etc.. using the next() function. This was ok for my server before trying to introduce GraphQL/Apollo, but now I want all this logic to be easily accessible to the Apollo resolvers.
I often hear that people are having an easy time turning their server from REST/non-GraphQL into a GraphQL server, but at the moment it's looking like it's going to be a bit of a job to go through all the logic and separate everything in to their own functions which take parameters directly rather than using the req object.
Is this a correct assumption? Or am I missing something?
Thanks!
Migrating the code you have shown above would be a very easy task. Once you build your graphql server and create your schema, etc. Then all you need to do is create login mutation. Then your resolver would handle the logic you have shown above. Then, instead of pulling the values from from req.body they would be function parameters.
A good pattern I am currently following is creating a login method on the model itself. Then the resolver calls the method on the schema (Here is an example of a project I'm doing it on now: Login method. Then here is an example of what the resolver looks like: Resolver
Hopefully that helped!

Nodejs importing controller into controller

I have appController, userController and noteController. I want import userController and noteController into appController
First, here is noteController
module.exports = {
index: (req, res) => {
Note.find({}).sort({
time: -1
}).exec((err, notes) => {
if (err) throw err;
res.send(notes)
});
}
}
And here is appController
const noteController = require('./noteController');
const userController = require('./userController');
module.exports = {
show: (req, res) => {
noteController.index((err, notes) => {
if (err) throw err;
res.render('index', {
notes: notes
});
});
}
}
I have started this project with only notesController to finally learn CRUD in Node but I am a little bit confused here. In my appController I want to index notes, and check if a user is logged in. If I am doing bad coding practice here, let me know.
There are definitely different approaches to follow to achieve what you're thinking about depending on the size of your application. That said, the general convention I see often is
1) You create User controller for your login endpoint, say /api/login
2) Create middleware to protect any routes that need user to be logged in
3) Store the user id in the request object(your middleware in #2 does this check and store the issue id in the request object so you can decode the user id and use it to make a query to your data service for notes belonging to that user)
That said, I assume your application might not need to drive in this direction. So this can work for you as well
const userController = (req, res) => {
/* Handle your logic here
Check that the user credentials match what is in DB
Check if the user has notes.
This might be two different queries to your DB(User and Notes tables(or collections)) depending on how you structure your schema.
You can now respond with the user `specific` notes e.g `res.render('notes', {notes: notes})`
*/
}
Hope this helps!

Resources