I'm using yup for validation and there's this amazing cast method that I would like to try, however it is not clear from the documentation, how do I get the error message in case of failure? cast either transforms and validates and returns the result or returns null and that's it. That's not acceptable - I also require an error message. At the same time I wouldn't want to run it twice, like - once for validation, once for cast.
cast either transforms and validates and returns the result or returns null and that's it
cast DOES NOT validate the result - it simply transforms it. validate(Sync)/isValid(Sync) casts and then validates.
If you want to provide an error message on a specific schema in case of failed cast you do it with typeError
At the same time I wouldn't want to run it twice, like - once for validation, once for cast.
As I said, the validate methods always run casting first before validating (if cast fails, then it doesn't run validation). If you want cast and validation functionality, then you just call the validation methods and it returns the cast result (if valid) - you don't need to call cast unless you ONLY want to cast (without validating).
You can throw Validation Error anytime you want.
Here is my full implementation:
phone: yup
.string()
// .test('is-valid', 'phone.invalid', async (value) => {
// if (typeof value === 'string') {
// const number = phoneUtil.parseAndKeepRawInput(value, 'TR');
// return phoneUtil.isValidNumber(number);
// }
// return false;
// })
.transform((value) => {
if (typeof value === 'string') {
const number = phoneUtil.parse(value, 'TR');
if (phoneUtil.isValidNumber(number)) {
return phoneUtil.format(number, PhoneNumberFormat.E164);
}
}
throw new ValidationError(
new ValidationError('phone.invalid', value, 'phone', 'is-valid')
);
})
.required()
.nullable(false),
Commented section is unnecessary and replaced in transform
The reason behind throwing nested Validation Error is completely because of my error parsing logic.
Related
I'm doing some debugging right now, and the problem appears to be that two incompatible types (string and integer) are being multiplied together. Right now, when these are multiplied together, a NaN result is returned. I want to run the code in a mode such that when incompatible types are multiplied together, an error is thrown instead. I tried running the code in strict mode ('use strict') but this did not work. How would I do this?
console.log(2*'a')
> NaN
Throw your own error, and handle appropriately, eg:
try {
if(isNaN( 2*'a')) throw new Error("not a number");
}
catch(err) {
// handle error here
}
Or check the type of the variable to handle appropriately, eg.
if (typeof(variableName) === "number")) {
console.log('variable is a number');
} else {
throw new Error('variable is NOT a number');
}
You can't change Javascript's behavior with this. The ES6 spec is specific on how this behavior works.
If possible, try to re-architect your code so a string can't be assigned to this variable in the first place. If that's not possible, checking for NaN manually as #yezzz suggests is the next best option.
Problem
When using mongoose to find documents by a specific field, if the type of the field is different from the type of the queried value, then mongoose will attempt to cast the query value to the same type as the field.
However, if the value cannot be casted, then mongoose will throw a CastError.
This behavior can be seen in the following example, where mongoose will attempt to cast the string 'invalid object id' to an ObjectId when trying to query for Foo documents by the bar field:
const fooSchema = new mongoose.Schema({
bar: {
type: mongoose.Schema.Types.ObjectId,
}
});
const Foo = <any>mongoose.model<any>('Foo', fooSchema);
await Foo.findOne({ bar: 'invalid object id' });
UnhandledPromiseRejectionWarning: Unhandled promise rejection
(rejection id: 1): CastError: Cast to ObjectId failed for value
"invalid object id" at path "bar" for model "Foo"
(Similar error would occur if bar was some other types, such as Number or Boolean as well.)
However, I don't like this behaviour. I very much prefer that the returned document simply becomes null, without an error being thrown. After all, if the value in the query cannot be casted, then the document logically also cannot exist under the given query.
Now, I am aware that I can simply do a check before constructing the query to ensure that I don't pass in a type that can't be casted. However, I don't like this approach because it results in having to duplicate code. Quite often, the code to handle what happens when the type is invalid will be exactly the same as the code to handle what happens if the document does not exist.
Additionally, I don't want to disable type checking completely either. So changing the type of the field to Mixed would not be a solution, as I would like the type check to still be there when I am creating a new document.
Attempted Solutions
So I attempted to solve this issue by creating custom query helpers to check the type, and return null if it is invalid, or perform the query if it is valid.
fooSchema.query.byBar = function(id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return null;
}
return this.where('bar').equals(id);
};
Which I can then use with Foo.findOne().byBar('invalid object id').
The problem with this solution however, is that it is no longer chainable. This means that if I were to try something such as Foo.findOne().byBar('invalid object id').lean(), it will throw an error if the type check fails (but will work fine when it passes the type check):
UnhandledPromiseRejectionWarning: Unhandled promise rejection
(rejection id: 1): TypeError: Cannot read property 'lean' of null
Trying to use static methods instead will run into the same problem.
fooSchema.statics.findOneByBar = function(id: any) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return null;
}
return this.findOne({ bar: id });
};
Question
So essentially, I want to be able to have the query return null if the type check fails, but still be chainable. I want the query to be chainable because I still want to be able to specify additional query conditions in the cases where the type is valid.
Now, if my attempted solution is on the right track, then what I need to do is instead of returning null directly if the type check fails, I return something from the chainable query builder api that will result in the query's final result to be null. I essentially need some sort of 1=0 query condition (however, the linked question did not propose a guaranteed answer for the 1=0 condition). So my question is, if my attempted solution is on the right track, then what do I return that is a chainable mongoose Query, but will cause the query to always result in null when the query is executed?
Or alternatively, if my attempted solution is on the wrong track, is there another way to make a mongoose find query result in null instead of throwing a CastError when the types are incompatible?
May be my answer is a bit silly and straight forward. But I would like to do it this way.
fooSchema.statics.findOneByBar = function(id: any) {
if (!mongoose.Types.ObjectId.isValid(id)) {
id = "111111111111111111111111"; // other values are also possible
}
return this.findOne({ bar: id });
};
This is a valid objectId and it may never be generated by Mongodb ever. So this way the query will be valid and all the chainable functionality will be intact. Let me know if it helps you.
Building off of the attempted solutions, I found two query conditions that seem to be functionally equivalent to 1=0.
1. Passing an empty array to the $in query condition.
fooSchema.query.byBar = function(id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return this.where('bar').in([]);
}
return this.where('bar').equals(id);
};
2. Using $where query condition that returns false.
fooSchema.query.byBar = function(id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return this.$where('false');
}
return this.where('bar').equals(id);
};
The advantages of these two solutions is that they work regardless of the type of bar and the possible values it may contain, as long as the type check is done correctly. That means we don't need to have prior knowledge of what values may or may not be stored in the fields, so arbitrary numbers and booleans are supported by these solutions as well.
The disadvantage of these two solutions is that such a query helper needs to be added for every field where we need to return null if the types don't match, and it needs to be repeated for every model. So we do not have the flexibility of the original mongoose query builder api anymore, as well as resulting in a lot of duplicate code.
Additionally, I'm not sure if either of these two conditions carry performance penalties.
If the flexibility of the mongoose query builder api is needed, a work around could be to use a try-catch statement, as it will catch the CastError that is thrown. Though it is a bit cumbersome to write.
let foo;
try {
foo = await Foo.findOne().where('bar').equals('invalid object id');
} catch (err) {
foo = null;
}
Though, if anyone have an even better solution, I am interested in hearing it.
Consider the following example:
Suppose there is a object with enum property. If enum property has 5 value, the field value should be equal to 5, if enum is super object must have properties up and down. So the js code can be like that:
if (obj.enum === 5) {
if (obj.value != 5) {
//error here
}
}
if (obj.enum === 'super') {
if (obj.up === undefined || obj.down === undefined ) {
//error here
}
}
How to integrate this code into loopbackjs???
E.g. this is not a fields validation (custom or not), this it model validation. So isValid funciton (see below) and validate method can not be used. The validate validates only one property.
Here is very similar question but it ended up with custiom property validation.
Here is example with isValid funciton in validatable.js. Please note that this only invoking validation, there is no way to add additional errors or add additional validation
Use this answer as workaround. Pass one of always present fields to validate method and add custom error code and messages inside customValidator funciton.
Does the following (anti?)pattern have a name?
every function returns an instance of a result class (or structure, or associative array) that has at least these two public variables:
success: a true/false value to hold if the action completed successfully
result: a variable that holds the result of the function or nothing if the function is void.
if success is false an error variable may hold information (exception/stack trace/debug) about the error
a message variable holding an user friendly message might be defined if error is not empty
only the result of the operation is encapsulated. Inputs are passed normally.
I've seen this used both in .Net and PHP (on server and in a script invoked by JavaScript/Ajax requests). Is it best practice? Is this an anti-pattern?
This is a common way to handle a procedure call that can return both failure or success and a value. As noted in the comments, it is fairly common when calling APIs. Alternatives include: a) combining the return value with the success/failure so it has to be known and checked externally in the calling code, b) using an out parameter to return the desired value on success, or c) throwing exceptions to indicate failure, which is expensive and silly, so I will not discuss further.
a) Combining the return value with Success/Failure
This requires the calling code to know what represents failure in the return value instead of being explicitly told it failed.
public string GetSomeString(int id)
{
//return a value on success or null on failure
}
So the calling code has to know that a null or empty string is failure and check accordingly...
var result = obj.GetSomeString(2);
if(string.IsNullOrEmpty(result))
{
//ooops, failed
}
And this, of course, isn't an option if null is a legitimate return value.
Similarly for an int call...
public int GetSomeInt(string someArg, bool someOtherArg)
{
//return a value or a -1 for failure
}
So the calling code has to know again what is bad and assume everything else it OK...
var result = obj.GetSomeInt("blah", true);
if(result == -1)
{
//ooops, failed
}
And again, doesn't work if your "error" value is legitimate in some cases (or worse becomes legitimate at a later time).
b) Using an out parameter to pass back a value on success
An other option is to return success or failure from the method and use an out parameter to return the value if successful.
public bool GetSomeString(int id, out string someString)
{
//if fail return false
//otherwise set someString = value and return true
}
So the calling code looks like this...
string goodString = null;
if(!obj.GetSomeString(2, out goodString))
{
//ooops, something bad happened
}
This offers the advantage of separating the success/failure of a call from the value it returns. It works, but it's a klutzy syntax and if you need to return more than value, you'll end up adding more out parameters or creating an object to return in the out anyway. It also can't tell you why it failed. Which brings us back to you to the subject of your question...
Using a Result object
This gives you the advantage of b) in that success/failure is unambiguously evident and does not require the calling code to have any knowledge of what return value might indicate failure. It feels cleaner because it doesn't require using the out syntax. It also provides the additional benefit of allowing you to indicate the reason for failure by passing it back along in the message property of the result object.
I want to be able to call a function in JavaScript and return a primitive value, but also data. For instance, let's say I want to validate a password. Sometimes I want to know if it's valid or not (meets minimum requirements), and sometimes I want to know how strong it is, and other times I want to know how strong it is in words ("weak, strong,", etc.).
So basically I want this to be valid:
if (validate.checkPassword(password)) ...
but also this to work:
if (validate.checkPassword(password).strength === "strong")
if (validate.checkPassword(password).rating >= 6)
Since an object can both be a function have data, can a JSON return value both have a primitive type base value, and other data members?
No, things can not be multiple typed. However, you could add a boolean to that data structure
if (validate.isValidPassword(passWord).isValid)...
but you should strongly reconsider your nomenclature, as that is some confusing stuff up there.
Otherwise, null is falsey, so if you only use the latter statements inside a block where it is valid, then you should have no problem.
First off, JSON is just the notation of a JavaScript object not what the object itself is called. Within JavaScript (unserialized) it's just an object.
With that said, it seems like you want to return an object back from your validation method which would then expose the various information you're looking to return. e.g.
function isValidPassword(pw){
var result = {
strength: 'weak',
rating: 0,
valid: false
};
// test and change result.strength, result.rating and result.valid
// based on the input
return result;
}
This is an either/or scenario so you can't return "true/false" and get that extra meta information. Note that any object returned would result in a true result when tested, so given the above:
var validPassword = validate.isValidPassword(null);
// always true, we have an object
if (validPassword){
}
// instead, you'd now need to check:
if (validPassword.valid){
}
(I'll also disregard that a name like isValidPassword implies a true/false result and not an object result so if you're making a common library I'd encourage you to rename the function if you plan to change the result)
However, you can make multiple methods to break out the level of detail you're looking for, which makes a simple isValidPassword work as intended, but then add functionality like getPasswordStrength, getPasswordRating, etc.:
function isValidPassword(pw){
// return true/false;
}
function getPasswordStrength(pw){
// return "weak","strong",etc.
}
function getPasswordRating(pw){
// return 1,2,etc.
}
This also keeps the implied results a little more legible in terms of readability while still offering alternatives to getting the information you're looking for.
if (!validator.isValidPassword(pw)){
error = pw + ' is unacceptable (' + validator.getPasswordStrength(pw) + ')';
}
return { strength: 'abc', rating: -1 }
Truthyness in javascript will make the if statement work, then you can inspect the JSON for any values needed.
Consider:
function PasswordInfo(strength, rating)
{
this.strength = strength;
this.rating = rating;
}
function isValidPassword(password)
{
return new PasswordInfo('strong', 10);
}
function validate()
{
var info = isValidPassword('password');
if (info.strength === 'strong' && info.rating >== 6)
{
alert('good password);
}
else
{
alert('bad password);
}
}
The function PasswordInfo in this instance is actually a class/constructor.
As far as I know, you can only return one 'thing' from your function, but the function can contain other 'things'.
I think your best result would be to return an object along these lines:
{
valid:
strength:
rating:
}
Then you could do what you're wanting above, with the exception of the default type where you'd need to do:
if (validate.isValidPassword(password).valid)
EDIT: As a slight justification to returning an object each time. In my mind I had imagined you would always want to check the state of why a password was valid or not. Simply returning false would give you the y/n for whether it passed, but wouldn't give you the info you'd need to establish 'why' the password was not valid.
If you wanted to display some 'you must include uppercase, lowercase and ensure that the first letter was typed on a Monday' type message then it would seem sensible to return the password 'result' object in every situation. Just seems more flexible to me.