How to override error message in #hapi/joi? - node.js

I am trying to override custom error message in Joi.
let's say i have a schema like follow.
const joiSchema = Joi.object({
name: Joi.string().required(),
email: Joi.string().email().required()
})
try{
const schema = joiSchema.validateAsync(req.body);
}catch(error){
error.details.map((detail) => {
// customize error message
});
}
I need to send error message like follow.
{ errors: { name: "Name is Required.", email: "Email is Required." } }
How to get fieldName like name in details array in Validation Error.

I found a workaround like below.
const errors = [];
err.details.forEach((detail) => {
const currentMessage = detail.message;
detail.path.forEach((value) => {
errors.push({ [value]: currentMessage });
});
});

You can just get the error and process like it
catch(error){
var data = data.details;
var message = data[0].message; // you can get other fields also like this
var json={"status":"0","message":message,"data":{}}; // you can customize your json response
}

Following approach too help
const errorList = [...errors];
errors.forEach((error, index) => {
const tmpError = { ...error };
tmpError.message = "Your custom error message";
errorList[index] = tmpError;
});
return errorList;

Related

Iterate dataArray to create an object is not happening

How can I parse the incoming nomData data array and store those values into an object along with userEmail ? Somehow below code is not working, could someone pleas advise the issue here.
Expected database columns values:
var data = { useremail: userEmail, nomineeemail: email, nomineename: name, nomineeteam: team, reason: reason }
server.js
app.post('/service/nominateperson', async (req, res) => {
try {
const userEmail = req.body.userEmail;
const nomData = req.body.nomRegister;
const formData = {
useremail: userEmail,
nomineeemail: {},
nomineename: {},
nomineeteam: {},
reason: {}
}
const newArray = nomData.map(item => {
formData.nomineeemail = item.email;
formData.nomineename = item.name;
formData.nomineeteam = item.team;
formData.reason = item.reason;
});
var data = { useremail: userEmail, nomineeemail: email, nomineename: name, nomineeteam: team, reason: reason }
// Ideally I should get nomData
//items parsed create an data object and pass that into bulkCreat() method:
const numberOfNominations = await NominationModel.count({where: {useremail: userEmail}});
if (numberOfNominations <= 3) {
const nominationData = await NominationModel.bulkCreate(data);
res.status(200).json({message: "Nomination submitted successfully !"});
} else {
res.status(202).json({message: "Nomination limit exceeded, please try next week !"});
}
} catch (e) {
res.status(500).json({fail: e.message});
}
});
So i assume nomData is an array containing multiple nominations. So if you want to bulkCreate with data you should pass an array instead of an object.
const data = nomData.map(item => ({
useremail: userEmail,
nomineeemail: item.email,
nomineename: item.name,
nomineeteam: item.team,
reason: item.reason
}));
...
await NominationModel.bulkCreate(data)

how to save an user profile picture in nodejs (upload an image in mongodb with nodejs)

I'm building a Nodejs application with a user profile update. All user information updates perfectly except for the image. I am not able to save the image neither locally nor in the database. Could someone help me solve this?
This is my code
For the controller
const {createUser, getUserPerUsername, searchUsersPerUsername, addUserIdToCurrentUserFollowing,
removeUserIdToCurrentUserFollowing, findUserPerId, updateUser, deleteUser} = require('../queries/users.queries')
const request = require('request')
const directoryUploads = require('../path').directoryUploads
const path = require('path')
const fs = require('fs')
const upload = require('../Middleware/upload')
exports.userUpdate = async (req, res, next ) => {
const userId = req.params.userId
const user = await findUserPerId(userId)
const body = req.body
try {
if(user) {
let picture = req.files['picture'] ? req.files['picture'][0].filename : null
console.log("Picture : " +picture)
const user = await findUserPerId(userId)
console.log("User Old : " + user)
if (userOld.picture) {
if (picture) {
const pathImagePreview = path.join(directoryUploads, 'uploads/') + user.picture
fs.exists(pathImagePreview, exists => {
if (exists)
fs.unlinkSync(pathImagePreview)
})
} else {
picture = user.picture
}
}
const userUptd = await updateUser(userId, {
firstname: body.firstname,
lastname: body.lastname,
"local.email": body.email,
phones: body.phones,
picture: body.picture
})
console.log("Image uploaded successfully !!")
req.flash('success', [`User ${userUptd.username} updated!`])
res.redirect('/users/profile')
} else {
throw new Error('Please make sure to fill in the fields correctly!')
}
} catch (error) {
console.log(error)
req.flash('errors', [error.message])
req.flash('body', body)
}
}
here picture refers to the name of the input type="file".
The error returned is "Cannot read property 'picture ' of undefined". I think that it's probably linked to the file retrieving
i think you have an undeclared variable :
userOld is undefined right ?
also this line is never used so i'm not sure if you really handled the upload :
const upload = require('../Middleware/upload')
do you use multer ?

FCM : getting ' Error: data must be a non-null object' error?

I am trying to send a push notification via Firebase cloud messaging. I am using Firebase admin sdk to send push notification in fcm . I am using nodejs
When I am trying to send a push msg , ...
I am getting this error
{
code: 'messaging/invalid-payload',
message: 'data must be a non-null object' },
codePrefix: 'messaging'
}
My code :
const admin = require('firebase-admin');
const serviceAccount = require(`${__dirname}/fet_firebase.json`);
function sendPushNot(to, body, sendId, type) {
const registrationToken = to;
const notification = {};
let message = { };
const pbody = { body };
if (type === 'User') {
pbody.userId = sendId;
notification.userId = sendId;
notification.title = 'New user Follwed';
}
if (type === 'Post') {
pbody.postId = sendId;
notification.postId = sendId;
notification.title = 'Post Liked';
}
if (type === 'Room') {
pbody.roomId = sendId;
notification.roomId = sendId;
notification.title = 'New Chat messsage';
}
message = {
data: JSON.stringify(pbody),
token: registrationToken,
notification
};
console.log('messgae',message);
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent cloud message:', response);
})
.catch((error) => {
console.log('Error sending cloud message:', error);
});
}
I thought that body is null
But the console output of console.log('messgae',message); is ::
{
data:
'{"body":"pankaj Liked Your Post","postId":"5ed1055ddf0efd2a42f6a28a"}',
token:
'f2umP-jfQyeM1suN77zz7-:APA91bHKzfqfRnmuBom2PIDB8cCPwZtq28JCWLSi1OMPO55JRzyhFZJpTkkNyDu_StTYID-scu-grejaxxn3d4iR6Xidz9-JCk_h-bRsdGHe8nzMrIVsc8vZDFgayiFgJrJ53DaDzb9b',
notification: { postId: 5ed1055ddf0efd2a42f6a28a, title: 'Post Liked'
}
}
So the body is not null
But I am getting data must be a non-null object' error ..
Why?
I fixed this by wrapping the stringified object with curly braces
data : { data: JSON.stringify(object) } // correct
data : JSON.stringify(object) // will result to the described error.
Data must be a non-null object. Above code sample is passing a string. Just remove the JSON.stringify() part.

Cannot Put error in postman..May I know what's the error..I have no problem in post and get request

/This is code that used to put request and change the team name
I don't know what is the question and I try many times and it keeps coming out cannot put error.../
obj.put('api/team/:number', (req,res)=>{
const tim = teams.find(t => t.number === parseInt(req.params.number))
if (!tim)
res.status(404).send("The team with the given number is not exist!");
const { error, value } = validationdata(req.body);
if (error){
res.send(error + "\nPlease try again!");
return;
}
tim.Team= req.body.Team;
res.send(tim);
});
function validationdata(nama){
const schema = Joi.object({
"Team" : Joi.string().min(5).max(20).required()
});
//const results = schema.validate(req.body);
return schema.validate(req.body);
};

How to change the default error output in restify

Is there any way that I can change the default error output? Say I'm going to change the rest error output:
{
"code": "InvalidArgumentError",
"message": "blah blah..."
}
to:
{
"code": 10001,
"message": "blah blah",
"extraMsg": "blah blah"
}
Here are some of my ideas:
Listen to the error events.
It seems like not all the RestError have emitted extra events (like NotFound, MethodNotAllowed, VersionNotAllowed... do). So I can't catch all the errors to rewrite them.
Listen to an event before response data sent.
I look through the official documents and have found nothing relative.
Modify the implementation of the RestError class.
Well it's obviously not a good approach.
Any other ideas?
Finally I provide a customized JSON formatter to get what I want:
var server = restify.createServer( {
formatters: {
'application/json': function customizedFormatJSON( req, res, body ) {
// Copied from restify/lib/formatters/json.js
if ( body instanceof Error ) {
// snoop for RestError or HttpError, but don't rely on
// instanceof
res.statusCode = body.statusCode || 500;
if ( body.body ) {
body = {
code: 10001,
scode: body.body.code,
msg: body.body.message
};
} else {
body = {
code: 10001,
msg: body.message
};
}
} else if ( Buffer.isBuffer( body ) ) {
body = body.toString( 'base64' );
}
var data = JSON.stringify( body );
res.setHeader( 'Content-Length', Buffer.byteLength( data ) );
return data;
}
}
} );
While the answers above might work, the easiest way to add a custom field to the error body is to call the restify error constructor with an object (hash) instead of a string. The object has to contain the body key which is what you will see in the browser.
For example:
return next(new restify.InvalidArgumentError({body: {field: 'password', message: 'Password has to be at least 6 characters long'}}));
or
return next(new restify.UnauthorizedError({body: {foo: 'bar', name: 'john doe', message: 'whatever error message'}}));
Restify offer many ways to implement error management : http://mcavage.github.io/node-restify/#Error-handling
Why don't you create a new error type "myError" just like sample code :
var restify = require('restify');
var util = require('util');
function MyError(message) {
restify.RestError.call(this, {
restCode : 'MyError',
statusCode : 418,
message : message,
constructorOpt: MyError
});
this.name = 'MyError';
}
util.inherits(MyError, restify.RestError);
For common errors I think that overloading methods is not such a bad idea... (I don't speak about modifying restify, just overloading functions using prototype)
(edited)
I was able to provide additional data adding a property to the body object.
Notice the this.body.errors = errors line
var restify = require('restify');
var util = require('util');
function ValidationError(message, errors) {
restify.RestError.call(this, {
restCode: 'ValidationError',
statusCode: 400,
message: message,
constructorOpt: ValidationError
});
this.name = 'ValidationError';
this.body.errors = errors; //<---
}
util.inherits(ValidationError, restify.RestError);
`
You can use restify-errors-options
Your example simply becomes:
const restify = require('restify');
const errors = require('restify-errors');
const errorsOptions = require('restify-errors-options');
errorsOptions.add('extraMsg');
const err = new errors.BadRequestError({extraMsg: 'whatever you want'});
err.toJSON();
//=> {code: 'BadRequest', message: '', extraMsg: 'whatever you want'}
Please also note that the solution provided was only tested on restify 5.x
Follow this issue for more information.

Resources