Ajv keywords and custom error messages - javascript

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.

Related

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 does not throw error when validate in schema matches false

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

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
}
})

Error: Unknown rule type username in ReactJS

I am new to ReactJs, I am Using Ant-design For Registration Form and applied some validation Rules. I want to validate User when user enter something in fields, message ( Username must be Unique ) is shown to the user for guidance . But when I enter something Error is occur Unknown rule type username.
Code of Form
<FormItem>
{getFieldDecorator('username', {
rules: [
{
type: 'username',
message: 'Username Must be Unique!',
},
{
required: true,
message: 'Please Enter Your Username',
},
],
})(<Input placeholder="Username" />)}
</FormItem>
You must be confusing type with something else.
According to this page: https://ant.design/components/form/ , type will rather be referenced to something like string or boolean.
EDIT:
...
{
type: string,
message: 'Username Must be a string',
},
...

Custom error messages for Groups within the jQuery Validation plugin

I'm using the jQuery Validation plugin and i've started to group some of my fields together:
groups: {
fullName: "myFirstName myLastName"
},
I've also added the fields to the rules section so that they are validated:
rules: {
myFirstName: {
required: true
},
myLastName: {
required: true
}
},
This works great and produces an error of "This field is required" for the group.
My question lies with custom error messages. I have the following setup:
messages: {
fullName: "Please enter both your first name and your last name"
}
Unfortunately the custom error doesn't show, only the generic one.
Does anyone have any ideas?
You have to use errorPlacement for this, and the message should be the same on both, for example:
messages: {
myFirstName: { required: "Please enter both your first name and your last name" },
myLastName: { required: "Please enter both your first name and your last name" }
}
Then, assuming they have the same IDs here, your errorPlacement option would look like this:
errorPlacement: {
var n = element.attr("name");
if (n == "myFirstName" || n == "myLastName")
error.insertAfter("#myLastName");
else
error.insertAfter(element);
}
The group itself has no message, it's just telling the plugin that they share a message label.

Categories