I am writing a route for registering users. There are three required fields, name, email and password.
How should I handle a missing field ?
Like this ?
function(req, res) {
if(!req.body.name || !req.body.email || !req.body.password) {
res.status(400).json({
"message": "All fields required"
});
return;
}
}
Or should I throw an error and pass it to my error handler like this :
function(req, res, next) {
if(!req.body.name || !req.body.email || !req.body.password) {
return next(new Error('All fields required'));
}
}
You can use a middleware to make sure your endpoints get what they are supposed to. Try Express Validator
Include:
var expressValidator = require('express-validator')
Then
app.use(express.bodyParser());
app.use(expressValidator([])); // place after bodyParser
At your endpoint you can either check fields in body, params, or query separately like
req.checkBody('age', 'Invalid Age').notEmpty().isInt(); //required integer
req.checkBody('name', 'Invalid Name').notEmpty().isAlpha(); //required string
req.checkBody('name', 'Invalid Name').isAlpha(); // not required but should be string if exists
//for params use req.checkParams and for query req.checkQuery
var errors = req.validationErrors();
if (errors) {
res.send(errors).status(400);
return;
}
Or you can define and use a schema in a separate file. Let's say userSignUp.js inside validationSchemas directory
module.exports = {
'name': {
optional: true,
isLength: {
options: [{ min: 3, max: 15 }],
errorMessage: 'Must be between 3 and 15 chars long'
},
errorMessage: 'Invalid Name'
},
'email': {
notEmpty: true,
isEmail: {
errorMessage: 'Invalid Email'
}
},
'password': {
notEmpty: true,
errorMessage: 'Invalid Password' // Error message for the parameter
}
}
And at point of validation:
var userSignUpSchema = require('./validationSchemas/userSignUp.js);
req.checkBody(userSignUpSchema);
if (req.validationErrors()) {
res.send(errors).status(400);
return;
}
For every use case you can add another schema file and validate the fields
For only validate if fields are empty, the best way is validate in the front. If you use HTML 5 it's possible to use require in the input, this way the form is not submmited. But, in javascript this is not problem too.
Definitely the first option. The second one may in fact crash your server if you don't have any error middleware (not sure about that though). Even if you had error middleware it would probably default to returning 500 - 400 is the proper response.
For required fields, instead of checking with the server and loading it more, you can simply do it in your front end. There are multiple ways of doing it. In HTML, there is a required attribute which you can set to true and it does not submit the form until all these required fields are filled.
To get more control over how the error is handled, you can verify the form using a form verification method on submitting it which checks for empty and/or invalid fields (Form validation). This can be done using jQuery, plain old JS, angular or whatever you'd like to use at the client side.
In case you want to keep it completely server side, the first option wherein you're checking for empty object attributes and returning an error JSON is how I'd do it.
Related
I made a form using NodeJs, i made some validations of input that show errors when user enter wrong values, the problem here is that the error appear on a new blank page but i need the error to appear on the main html file itself with cool styling
here's the live site http://mido.sundays.org.uk
I tried to make post request on the same route to see if the error will appear on the same page or not but the page turned to white blank page with the text inside
app.post('/', function (req, res) {
const SchemaValidation = {
name: joi.string().min(4).required().error(() => {
return {
message: 'Name is required. (min:4 chars)',
};
}),
email: joi.string().email().error(() => {
return {
message: 'Email field can\'t be Empty',
};
}),
phone: joi.string().min(8).max(14).required().error(() => {
return {
message: 'Valid Phone number is Required (min:8 characters - max: 14 characters)',
};
}),
university: joi.string().required().error(() => {
return {
message: 'University Field is Required',
};
}),
faculty: joi.string().required().error(() => {
return {
message: 'Faculty Field is Required',
};
}),
academicyear: joi.string().required().error(() => {
return {
message: 'Academic Year Field is Required and should range from 1-6',
};
}),
workshop: joi.array()
.items(joi.string().error(() => {
return {
message: 'You Should pickup 2 Committees',
};
})),
first_choice: joi.string().required().error(() => {
return {
message: 'You should pickup first choice',
};
}),
second_choice: joi.string().required().error(() => {
return {
message: 'You should pickup second choice',
};
}),
};
joi.validate(req.body,SchemaValidation,(err, result) => {
if(err) {
res.send(`<p style='color:red; text-align:center; margin-top:20px;'>${err.details[0].message}</p>`);
return; // don't try saving to db if the schema isnt valid
}
else
res.send(`<p style='color:green; text-align:center; margin-top:20px;'>Successfully Posted Data</p>`);
})
});
All what i need is to show the error in the same page and prevent the submit..
To solve this problem, I highly racommand you to use Pug.js (Template Engine), because you can't pass parameters into a specific page. By using a template engine, you can pass data as object, and render them with res.render('index', {error: res.error.message}).
You will be able to output into the page from server side the error object displaying whatever you needed to display!
res.send('content') basically it's a document.write()
https://pugjs.org/api/getting-started.html
Is there a reason you can't do the validation on the front end before submitting the form? That is usually the preferred way. You can have some backend validation so that you don't get bad data into your db but once you send a request you need to send a response back and in your case the response is the message not the entire HTML page. You can create a validation by adding an event listener to your submit button then using Ajax once you validate to send the data to the backend or you can use Bootstrap's built in validation and not mess with Ajax just through the form action. https://getbootstrap.com/docs/4.0/components/forms/#validation
I have created a login section using Vuex and Axios to authenticate the login by allowing the user to enter the email and password. I have created and stored the variables I need by using a getter. I have also, placed the tokens I needed into a function, post url and console.
But, know I need to show the responses according to the tokens being seen in the inspector/console.
What I need is to show the error messages when the user tries to login. So, when the console responds showing 200 (email and password is correct) I need it to store that token, when the console responds showing 400 (incorrect/missing characters in either email or password) I need it to print out the error messages that I have already placed with an array, lastly, when the console responds showing 401 (both email and password incorrect) I need it to print out the messageFour that is in the array.
HTML:
<template>
<form>
<div class="login">
<div>
<input type="text" v-model="email" placeholder="Email" class="eSection" id="email">
<p v-for="message in errorM" :key="message.errorM" v-show="message in errorM">
{{ message }}
</p>
<input type="password" v-model="password" placeholder="Password" class="pSection" id="password">
<p v-for="message in errorM" :key="message.errorM">
{{message}}
</p>
<button type="button" class="log" #click="login">LogIn</button>
</div>
</div>
</form>
</template>
Javascript:
<script>
import axios from 'axios';
export default {
data() {
return {
email: "test#gmail.com",
password: "123456",
flag: false,
errorM:[],
errorMessages: [
{
messageOne: "The email that has been entered is incorrect. Please try again!"
},
{
messageTwo: "Email/Password is missing. Please try again!"
},
{
messageThree: "The password that has been entered is incorrect. Please try again!"
},
{
messageFour: "Both Email and Password that have been entered are incorrect!"
},
]
}
},
methods: {
login: function (index) {
axios.post(`https://api.ticket.co/auth/login`, {
email: this.email,
password: this.password
})
.then(response => {
// JSON responses are automatically parsed.
console.log(response.data)
console.log(response.status)
})
.catch(e => {
console.log(e)
console.log(e.response.status)
var vueObject = this
switch (e.response.status) {
case 400:
if(!vueObject.email || !vueObject.password){
vueObject.errorM.push(vueObject.errorMessages.messageTwo)
};
if(!vueObject.email){
vueObject.errorM.push(vueObject.errorMessages.messageOne)
};
if(!vueObject.password){
vueObject.errorM.push(vueObject.errorMessages.messageThree)
};
break;
case 401:
if(vueObject.email && vueObject.password == ""){
vueObject.errorM.push(vueObject.errorMessages.messageFour)
}
break;
}
})
},
},
}
</script>
Many thanks!
It's not clear from the description what's not working, so I'll just point out some issues I see.
One thing to mention is, there is no evidence of you using vuex, no getters, no setters, no state.
Most notable is that you have the messages defined as an array of objects, which makes it difficult to look up
instead of this, which is harder to look up:
errorMessages: [
{
messageOne: "The email that has been entered is incorrect. Please try again!"
},
// etc... {}, {}, {}
]
... you should do
errorMessages: {
messageOne: "The email that has been entered is incorrect. Please try again!",
messageTwo: "Email/Password is missing. Please try again!",
messageThree: "The password that has been entered is incorrect. Please try again!",
messageFour: "Both Email and Password that have been entered are incorrect!",
}
so that you can find a message using this.errorMessages.messageTwo
Or better yet, define it outside of your vue component, since you're not using them in your template
const MESSAGE_INCORRECTEMAIL = "The email that has been entered is incorrect. Please try again!";
const MESSAGE_MISSINGFIELD = "Email/Password is missing. Please try again!";
const MESSAGE_INCORRECTPASSWORD = "The password that has been entered is incorrect. Please try again!";
const MESSAGE_INCORRECTEMAILPASSWORD = "Both Email and Password that have been entered are incorrect!";
and then just call them as MESSAGE_MISSINGFIELD from your script
From security standpoint, it's a bad idea to indicate whether the username or the password is wrong, as it makes hacking easier by confirming what usernames exist.
You can determine if the user had errors or fields are missing before sending the form for remote processing.
to do that, you would call
login: function (index) {
if (this.email.trim() === '' || vueObject.password.trim() === ''){
this.errorM.push(MESSAGE_MISSINGFIELD);
return // <- prevents further execution
}
// repeat for other local validations before remote request
// ... then process request
axios.post(`https://api.ticket.co/auth/login`, {
anyway, you might also need t break your question up into individual errors you encounter.
In Sails.js it is possible to use different database connections for models and it is easy to change database (MySQL or MongoDB). The problem arises when I want to display validation errors. These are my codes:
Groups.js model
...
connection: 'MysqlConnection', //or connection: 'MongodbConnection'
attributes: {
id: {
type: 'string',
unique: true
},
name: {
type: 'string',
required: true
},
...
GroupsController.js controller:
...
//add group to database
Groups.create(group, function (err, data) {
if (err) {
console.log(err);
res.send('Error'); // is it possible to send only validation error
return;
} else {
res.send(data);
}
});
...
Should I handle each attribute validation error separately, is it possible to send only validation error?
MySQL returns:
Error (E_VALIDATION) :: 1 attribute is invalid ...
MongoDB returns:
Error (E_UNKNOWN) :: Encountered an unexpected error ...
you can try:
Model.catch(function(err) {
var inspect = Object.keys(err)// [ "reason","invalidAttributes", ".." ]
console.log( Object.keys(err.invalidAttributes) ) // ["name","etc.."]
})
to catch the error
I would like to perform server side validation, preferably with expressValidator. When saving a resource, I check to see if it is valid. If it's not valid what should I return?
There are examples:
http://blog.ijasoneverett.com/2013/04/form-validation-in-node-js-with-express-validator/
https://github.com/ctavan/express-validator
Unfortunately, I can't figure out my answer from that.
In Angular, I am using the $resource service. When I do a save, and there is a validation error, how should the server send this back? Note, this is a single page application.
Also, how should I handle this on the client side? Is this technically a success call?
Please, I am not looking for any instant, ajax, check per field solution. I want to submit save, if there is a problem, I would like to return the errors so that Angular can handle them. This does not need to be the perfect solution, just something to set me on the right track.
I am not handing the Angular code in an special way at the moment:
Controller:
$scope.saveTransaction = function (transaction) {
transactionData.saveTransaction(transaction);
}
Service
saveTransaction: function(transaction) {
return resource.save(transaction);
}
The server side code looks as follows:
app.post('/api/transactions', function (req, res) {
var transaction;
req.assert('amount', 'Enter an amount (numbers only with 2 decimal places, e.g. 25.50)').regex(/^\d+(\.\d{2})?$/);
var errors = req.validationErrors();
var mapped = req.validationErrors(true);
if (mapped) {console.log("MAPPED")};
//console.log(mapped);
if(!errors) {
console.log("Passed");
transaction = new TransactionModel({
date: req.body.date,
description: req.body.description,
amount: req.body.amount
});
transaction.save(function (err) {
if (!err) {
return console.log("created");
} else {
return console.log("err");
}
return res.send(transaction);
})
}
else {
console.log("Errors");
res.send(errors);
// res.render('Transaction', {
// title: 'Invalid Transaction',
// message: '',
// errors: errors
// });
}
});
You could send and handle "better" errors:
SERVER
res.json(500, errors)
CLIENT
resource.save(tran).then(function(){
//it worked
},
function(response) {
//it did not work...
//see response.data
});
I added a validation to a Model and a Collection wont fetch the models who arent valid. (Btw I use coffeescript so the examples are in coffeescript)
Somebody knows a solution for this? The following isnt working
collection = new UserCollection
collection.fetch({
silent: true
success: ->
console.log('collection.models:', collection.models)
})
UPDATE 1
I have a lot of users without a mobile number.
User Collection:
class UserCollection extends Backbone.Collection
url: ->
app.routes.users_url
User Model:
class User extends Backbone.Model
idAttribute: '_id'
defaults: {
"email": null
"mobile": null
"loc": null
}
url: ->
app.routes.users_url + '/' + (#id || '')
validate: (attrs) ->
if !attrs.email
return "Email address must be provided"
if !attrs.name
return "Name must be provided"
if !attrs.mobile
return "Mobile number must be provided"
if #isNew() and attrs.password != undefined
if !attrs.password
return "Password must be provided"
if attrs.password != attrs.password_confirmation
return "Passwords do not match"
model: User
UPDATE 2
ok i temporary fixed it by hacking the backbone.js.
It is happening in function _prepareModel
I changed this line:
if (model.validate && !model._performValidation(attrs, options)) model = false;
into this line:
if (!options.silent && model.validate && !model._performValidation(attrs, options)) model = false;
It is not a solution so i keep this question open
"I added a validation to a Model and a Collection wont fetch the models who arent valid.
(Btw I use coffeescript so the examples are in coffeescript)"
If your models don't validate you have a problem with your models or your validation.
"I have a lot of users without a mobile number."
In your validation you have:
if !attrs.mobile
return "Mobile number must be provided"
you could define a parse function in your collection to log what models are coming from the server (parse() gets passed the raw response from fetch())
parse: function(response) {
console.log(response.results);
return response.results;
}
or you can take the line that validates the existence of a mobile number out of your validation since you don't know if the user has a mobile number.
and just to cover all the bases, defining an error function for fetch() should help you:
collection.fetch({
silent: true
success: ->
console.log('collection.models:', collection.models)
error: (collection, response) ->
console.log('response')
})
When you validate your model, check for model.silent and only validate if that doesn't exist.
So you do the following when you want to fetch a model:
var test = new MyModel({ id: '123', silent: true });
// in your Model validate function
validate: function(attrs) {
if (!attrs.silent) {
// validate logic here
}
}
Then you can fetch the model. After you get your model you can unset silent.