Mongoose: E11000 duplicate key change the type of return message in case of error - javascript

The following message is returned to me: E11000 duplicate key error collection ..., when one of the attributes that is specified as unique: true, it would be possible to modify this error message with a custom one for example:
{error: '11000', field: 'name of the field giving the problem'}

Uniqueness in mongoose is not a validation parameter, so you can't create custom error message for these fields, it is only to create uniqueness index in DB.
What you can do is, create a Error Handling middleware in Mongoose, and intercept 11000 errors, and send a custom error message in response.
From Mongoose documentation
// Handler **must** take 3 parameters: the error that occurred, the document
// in question, and the `next()` function
schema.post('save', function(error, doc, next) {
if (error.name === 'MongoError' && error.code === 11000) {
next(new Error('There was a duplicate key error'));
} else {
next();
}
});
Note: This allows you to catch 11000 duplication key error, but it doesn't tell you which field caused thee problem.

Related

Firebase - How to extend FirebaseError?

I am implementing a cloud function for signing up with unique username and password.
In order to throw exceptions, I was previously doing the following:
signUpValidation.js
if (!validateUsername(username)) {
throw new functions.https.HttpsError(
"invalid-argument",
"Invalid username.",
{
status: "error",
code: "auth/invalid-username",
message: "Username must be between 3 and 30 characters, including numbers, letters, hyphens, periods, or underscores.",
}
);
}
signUp.function.js
try {
await validateSignUpData(
username,
email,
password,
repeatPassword,
name,
birthday,
clientIp
);
} catch(err) {
if (err instanceof functions.https.HttpsError) {
throw err;
}
// An unknown error has occurred
console.error(err);
throw new functions.https.HttpsError(
"unknown",
"Unexpected error.",
{
status: "error",
code: err.code ?? "unknown",
message: err.message ?? "The registration request could not be processed. Please, try again later."
}
);
}
But, I don't really like this way of throwing the exceptions in the signUpValidation module... it makes more sense to me to throw "AuthErrors" instead of "HttpsErrors".
So, as it seems not possible to extend the default Firebase Errors, I have decided to create my own util/authErrors module:
class AuthError extends Error {
constructor(code, message) {
super(message);
this.code = code;
this.name = "AuthError";
}
}
const authErrors = Object.freeze({
usernameAlreadyExists(message = "The username is already in use by an existing account") {
return new AuthError('auth/email-already-exists', message);
}
... more errors
});
module.exports = authErrors;
as you can see, I have created my custom Error and some factory functions for every error type. Then, in my signUpValidation.js, I just do:
if (!(await isUsernameUnique(username))) {
throw authErrors.usernameAlreadyExists();
}
Is it possible to extend a FirebaseError? If not, why?
Is it considered a bad practice to work this way in order to throw custom exceptions in Cloud Functions? I mean, should I just throw HttpsErrors?
Having Custom Error Type is useful if you are going to treat it differently.
For example if you have a try/catch block and want to have a different logic for your custom error.
but here you are passing error to client which has no idea of either Firebase HttpsError or your custom AuthError. because at the end your object will be serialized to JSON and at the other end there is no class to convert it back to HttpsError or AuthError.
Also at HTTP protocol level, authentication errors are defined by HTTP status codes (e.g. 401 ,403) so they are not inherently different object types.
What I'm saying is that I don't see any advantage in having a custom AuthError class on your server side when it can not be transformed as it is to your client to be treated differently.
For client the HTTP status code is the key to differentiate an Auth error from other type of errors.

"Cast to ObjectId failed for value ...." error. Wanting to intercept to create my own error message but getting confused

I just graduated from a Full Stack Bootcamp and this is my first post. I am still trying to learn and apply all of this stuff. Working on a portfolio project for a server using NodeJs/MongoDB/Mongoose and am trying to figure out how to intercept the .catch error and generate my own error message. I'm making a PUT request using an object ID for a specific record and everything is working when a valid ID is passed. However, if I test using an invalid ID it goes straight to catch error and bypasses my handling of this type of scenario. Here is the code I'm trying to manipulate:
.put((req, res, next) => {
Guitar.findByIdAndUpdate(req.params.guitarId, {$set: req.body}, { new: true })
.then(guitar => {
if (guitar) {
console.log(guitar);
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(guitar);
} else {
res.statusCode = 403;
res.setHeader('Content-Type', 'text/plain');
res.end(`${req.params.guitarId} does not match any guitars in database`);
}
})
.catch(err => next(err));
})
I assumed that if I tried to pass an invalid ID then if(guitar) would return false, then return my error code. But instead it appears that if an invalid ID is sent then it never gets to that point, instead giving the "Cast to Object Id" failure outside of my if/else code. Am I approaching this incorrectly? Thanks in advance for any insight!!!
The Cast to ObjectId failed is occurring before the find operation is sent to the server, so there is never a chance for the promise to resolve and move on to the .then.
You might try explicitly casting the value to ObjectId inside a try-catch block to handle that specific issue, or add some to the .catch for that error.

Amazon Web Services DynamoDB Error

I'm using Dynamoose to handle DynamoDB requests and actions in Node.js.
I'm getting this error when I try to get a record tho. (email is a variable defined earlier)
User.get({ 'email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
}
err is returning
ValidationException: The parameter cannot be converted to a numeric value: [object Object]
Any ideas why I would be getting this error?

Access denied [403] when updating user accounts client-side in Meteor

I'm reading through the docs for Meteor here and the useraccounts package here but can't find an answer. I've added the useraccounts package successfully and have created a few users, but now I want to add some data to the record in the collection for a given user.
For example, after account creation and login. I want the user to be able to add/edit some fields on their record (short biography, etc..), but I keep getting a 403 error whenever performing a Meteor.users.update(..).
My login config file can be found here.
The code that's causing an error:
Template.editProfile.events({
'submit form': function(e) {
e.preventDefault();
var profileInfo = {
displayName: $(e.target).find('[name=displayName]').val(),
tagLine: $(e.target).find('[name=tagLine]').val(),
aboutMe: $(e.target).find('[name=aboutMe]').val()
};
Meteor.users.update(
{ _id: Meteor.userId()},
{ $set: profileInfo},
function (err) {
if(err) {
console.log('there was an error submitting editProfile data');
console.log(err);
} else {
Router.go('profile');
}
}
);
}
});
Doing console logs show the Meteor.userId() coming back correctly so I'm not sure what the problem is. I'm assuming it's an issue with allow/deny but I don't even know where to begin to troubleshoot.
The exact error is:
error: 403
errorType: "Meteor.Error"
message: "Access denied [403]"
reason: "Access denied"
By removing the insecure package, client-side write access will be denied by default.
If you want to allow clients to write directly to a collection, you need to define rules.
For example:
Meteor.users.allow({
update: ownsDocument
});
ownsDocument = function (userId, doc) {
return doc && doc.userId === userId;
};
The ownsDocument() function checks if the userId specified owns the document. In addition to the update callback, you can set rules for insert and remove.
Read more about Meteor's collection.allow(options), access a demo app or clone the repository.

How to throw an error message to the client when check() throws an Match.Error?

I am publishing some documents from the Products collection, and using check() to ensure the options passed to it are valid. If the client passes in invalid options, I want to have a customized error message displayed on the console.
I am using the audit-argument-checks package to ensure I have checks for all methods and publish functions.
On the client, I passed in an invalid option (reverse should be a boolean), but no errors are observed on the client console nor the server log.
// Server
Meteor.publish('products', function (opts) {
try {
check(opts, {
sort: Match.Optional(String),
reverse: Match.Optional(Boolean),
start: Match.Optional(Number),
limit: Match.Optional(Number),
userId: Match.Optional(String)
});
} catch (err) {
this.error(new Meteor.Error('invalid-opts', "Please check your options are valid")); // Throws back an error saying invalid options
}
// Some more code
});
// Client
Template.home.helpers({
productListings: function () {
Meteor.subscribe('products', {sort: 'created', reverse: 'asdasd'});
return Products.find({});
}
});
I have tried using Match.test() in place of check(), but this does not satisfy the audit-argument-checks package, and I'd want to use it to ensure I don't miss any checks.
How can I throw an error message to the client when check() throws an Match.Error?
I looks like you are just failing to check for the error with a callback on the client. See the onError callback of Meteor.subscribe().
I have done your subscribe as below in a Meteorpad and it goes to the client for handling as expected.
Meteor.subscribe('products',{sort: 'created', reverse: 'asdasd'},
{onError: function( err ) {throw err;}}
);

Categories

Resources