Mongoose does not throw error when validate in schema matches false - javascript

I created custom generic validation functions for most common scenarios in my application, for example email validation, phone number validation and date/time validation.
validation of time (HH:MM format):
validateTime: (time) => {
return [new RegExp(HHMM_TIME_FORMAT).test(time), 'Wrong time format. Expected hh:mm']
}
Usage in model:
...
visitHourStart: {
type: String,
validate: modelValidator.validateTime
}
...
Given VisitHourStart value: x08:30x,
validateTime returns false - this is good behavior, but it does not throw error with given message. Document is being saved to database with wrong time.
How to tell my model to throw an error on unsuccessful validation?
EDIT1:
Changing validate: modelValidator.validateTime to
validate: {
validator: time => new RegExp(HHMM_TIME_FORMAT).test(time),
message: 'Wrong time format. Expected hh:mm'
}
inside schema does not work, still no error getting thrown and document is saved.

validate parameter expects an object representing Custom Validator like below:
visitHourStart: {
type: String,
validate: {
validator: time => new RegExp(HHMM_TIME_FORMAT).test(time),
message: 'Wrong time format. Expected hh:mm'
}
}
you can also specify RegExp type directly instead of arrow function:
visitHourStart: {
type: String,
validate: {
validator: new RegExp(HHMM_TIME_FORMAT),
message: 'Wrong time format. Expected hh:mm'
}
}
EDIT: in your example you're passing an arrow function which returns an array while Mongoose expects an array to be specified directly like below:
validate: [
new RegExp(HHMM_TIME_FORMAT),
'Wrong time format. Expected hh:mm'
]
I've tested all the three above ways and the error gets thrown each time

Related

In DymanoDB/Dynamoose, how can I set a schema of a map of string keys and number values?

So I have this instructions:
Schema Defs:
Result object:
It's a map of string keys and number values
"result": { "M": { [STRING]: { "N": "401" } },
This is what I have so far
result: {
type: Object,
schema: {
// I am getting 2 errors:
// Parsing error: Unexpected token, expected "]"
// ',' expected.
[id: String]: Number
},
required: true
},
Any ideas?
[id: String] is a TypeScript thing. Not allowed in standard JavaScript.
This is not technically possible in Dynamoose. The only option here is to use the saveUnknown schema setting.
This was brought up in a conversation before, and the user who wanted to do this I told to create an issue on the GitHub repo but it doesn't look like that happened. If you'd like support for this in Dynamoose in the future, please submit a feature request on the GitHub repo.
Edit
In order to do this your schema would looks something like:
new dynamoose.Schema({
result: {
type: Object,
required: true
},
}, {
"saveUnknown": ["result.**"]
});
This will allow indefinitely nested objects within result.

How to avoid overriding the property in an object to be null when no parameters are passed in REST api?

I am building a project in REST API. One of my models is reservation as described below.
const reservation = new mongoose.Schema({
customerName: {
type: String,
required: true,
minlength: 3,
maxlength: 50
},
date: { type: Date, required: true },
message: {
type: String,
minlength: 3,
maxlength: 250
}
})
I am building a PUT route to update the reservation (shorter version below for simplicity)
router.put('/:id', async (req, res) => {
const { customerName, message, date } = req.body;
const reservation = await Reservation.findByIdAndUpdate(req.params.id, { customerName, message, date: new Date(date) }, {
new: true
});
res.send(reservation);
});
If the client doesn't pass the req.body.message it becomes null in the database. Which makes sense. But what is the way to, instead of overwriting the message to null, just ignore it, and keep the message as it is? There has to be a better way then writing if statements and conditions.
Rule of thumb : DO NOT accept any input as it is. You should validate the payload.
The cleanest solution is to return 422 status code message if some fields are missing or not validated based on your data format.
For example; if customerName is required field and it should be in a specific format and type but client does not send this field or send the field with empty value or too long or not correct data type then return 422 http status code with error response to explain what the issue is.

Mongoose saving empty array error "TypeError: Cannot read property '1' of null"

I have a schema that is defined like so:
const userSchema = new Schema({
...
surveys: [surveyKeySchema],
...
})
Where surveyKeySchema is actually a subdocument scheme defined like so:
const surveyKeySchema = new Schema({
slug: {
type: String,
required: 'Please supply a slug',
unique: true,
lowercase: true,
trim: true
},
name: {
type: String,
required: 'Please supply a name',
trim: true
},
responseCount: {
type: Number,
default: 0
}
})
Now whenever I try to modify anything on the user except for this array, everything goes fine. When instantiating the user, it is also totally fine. I can also call await user.save() in my code right before I empty the array.
It's also fine when I remove any subdocument from the survey as long as there is at least 1 element remaining.
However, when I try to remove the final subdocument using:
await user.surveys.id(sid).remove()
await user.save()
I get an error on the .save() which is just TypeError: Cannot read property '1' of null. I'm confused and can't find anything about this online, I assume it must be requiring at least one subdocument to be present? Is there any way to remove this, or if my assumption is wrong how would I go about resolving this?
Thanks in advance! And my apologies if I'm missing something obvious!
EDIT:
I found that mongoose's mongo error handler was actually throwing this in a regex it was using to parse the error message. Hacking this around to return the raw error message:
E11000 duplicate key error index: db.users.$surveys.slug_1 dup key: { : null }
As per this question I tried adding sparse: true but this didn't work.
For anyone else having this issue, here's what I did:
In node_modules/mongoose-mongodb-errors/lib/plugin.js on line 19, add a simple console.error(err.message) so you can actually get the output and not the regex handler error.
Because when you save an empty array of subdocuments in Mongoose it is equivalent to having the subschema set to values of null, this means that when Mongoose evaluates the indices of your subdocument collection it will evaluate it as having a value of null for each property. If you're indexing with a property (i.e. one of the properties in your subdocument schema has unique: true on it) then this is a violation as a null value cannot be unique, at least not in Mongo world. To get around this you can add sparse: true.
Any documents in the existing collection and the existing collection itself will create an issue with now having a changed index. You need to drop the index for this to work. I dropped the entire collection because I didn't need it anyways.
Here's my updated schema:
const surveyKeySchema = new Schema({
slug: {
type: String,
required: 'Please supply a slug',
unique: true,
lowercase: true,
sparse: true,
trim: true
},
name: {
type: String,
required: 'Please supply a name',
trim: true
},
responseCount: {
type: Number,
default: 0
}
})

Joi Validations: Capture the value passed in Custom Error Message

I am using Joi Library with NodeJs/Typescript for validations.
Validating a request body for a Post Operation.
I am using the language option to provide custom messages for respective field validations.
Below is the code
const bodySchema = Joi.object().keys({
// had to change from string to any so as to avoid multiple messages when empty
field1: Joi.any().required().valid('Dummy').options({
language: {
any: {
// wrt empty: specific error message not displaying with any but empty error is handled by allowOnly custom message. Anways there is no custom message for empty in requirements
// empty: '!!The parameter \'field1\' cannot be empty. It must be \'Dummy\'',
required: '!!The parameter \'field1\' is mandatory and must be the value \'Dummy\'',
allowOnly: '!!Invalid value for parameter \'field1\'. It must be \'Dummy\''
// how to capture value passed for field1 in the message?
}
}
}),
How to Capture the wrong field value passed as requestBody in the custom error message
For eg if I pass request body for the POST endpoint
{
"field1": "wrongvalue",
}
Expected custom message
Invalid value 'wrongvalue' for parameter \'field1\'. It must be \'Dummy\''
I have gone through JOI API but could not find any reference to doing this.
While regex option has the facility to capture the value passed.
{{value}} works in regex but not in other options.
Please let me know if there is a way to capture the value.
try this ......
const typeSchema = Joi.object({field1: Joi
any()
.required()
.valid('Dummy')
.error(errors => {
errors.forEach(err => {
switch (err.type) {
case "string.base":
case "required":
err.message = "field 1 is mandatory and must be the value";
break;
case "any.allowOnly":
err.message = "field1 must be Dummy";
break;
default:
console.log('validate error type missing', err.type);
break;
}
});
return errors;
}),
})

Ajv keywords and custom error messages

I have written a schema but it does not seem to be validating as I was expecting. I'm assuming there is something wrong with my schema syntax but cannot figure it out. I expect not to see error messages for title or target until fundraiser is complete since they are only required if fundraiser is completed. I've tried many combinations but none of them are working as expected, these two are the closest I've come to what I need.
Schema attempt one: shows 4 error messages, 3 required errors and 1 error saying data should match "then" schema.
const schema = {
required: ['fundraiser'],
if: {
properties: {
fundraiser: { type: 'string' },
},
},
then: {
required: ['title', 'target'],
},
errorMessage: {
required: {
fundraiser: 'Please select an option',
title: 'Please enter a title',
target: 'Please enter a target',
},
},
};
Schema attempt two: shows 2 error messages, 1 required error and 1 error saying data should match "then" schema which is correct but then when I complete fundraiser valid becomes true which is when I expect to then see required errors for title and target. Also no errors have my defined custom error messages.
const scema = {
if: {
properties: { fundraiser: { minLength: 2 } },
then: { required: ['title', 'target'] },
},
then: { required: ['fundraiser'] },
errorMessage: {
required: {
fundraiser: 'Please select an option',
title: 'Please enter a title',
target: 'Please enter a target',
},
},
};
I am pretty sure that I am doing something wrong with my schema but it is not clear from the documentation how to use if/then in combination with custom error messages using ajv-errors. Any help would be greatly appreciated! Thanks!
The problem with the first schema is that subschema inside “if” is valid, unless fundraiser property is present and not a string. It would probably work as you expect if you add type: 'object' to the root schema and move required inside “if” subschema.
The problem with the second subschema is that the first “then” that has no “if” in the same schema object is ignored (unless you are using ajv-keywords that implemented if/then/else somewhat differently from how it is defined in draft-07 of JSON Schema spec) and the subschema inside “if is valid even if fundraiser property is absent and the second “then” can only pass if fundraiser is present.

Categories