Sequelize validation error

const User = sequelize.define('User', { password: { type: DataTypes.STRING, allowNull: false, validate: { len: { args: [ 8, Infinity ], msg: "Password must be at least 8 characters.&qu...

Hee’s my code from the user’s model
`
module.exports = function (sequelize, DataTypes) {
const { models } = sequelize

const user = sequelize.define('user', {
	first_name: {
		type: DataTypes.STRING,
		validate: {
			is: ["^[a-z]+$", 'i'] // only allows letters
		}
	},
	last_name: {
		type: DataTypes.STRING,
		validate: {
			is: ["^[a-z]+$", 'i'] // only allows letters
		}
	},
	phone: {
		type: DataTypes.STRING,
		unique: true
	},
	email: {
		type: DataTypes.STRING,
		validate: {
			isEmail: true
		}
	},
	languages_spoken: {
		// If sync({force:true}), then I cannot use an ENUM. If force is set to false, then I can use an enum
		type: DataTypes.ARRAY(DataTypes.STRING),
		defaultValue: ['en']
	},
	country: {
		type: DataTypes.STRING,
		defaultValue: 'United States of America'
	},
	country_code: {
		type: DataTypes.STRING
	},
	passcode: {
		type: DataTypes.STRING
	},
	passcode_expiration: {
		type: DataTypes.DATE
	},
	verified: {
		type: DataTypes.BOOLEAN,
		defaultValue: false
	},
	profile_picture_string: {
		type: DataTypes.STRING
	},
	avatar: {
		type: new DataTypes.VIRTUAL(DataTypes.STRING, ['profile_picture_string']),
		get: function () {
			if (this.get('profile_picture_string')) {
				return `${env.AWS_PREFIX}${this.get('profile_picture_string')}`
			} else {
				return null
			}
		}
	},
	position: {
		type: DataTypes.GEOMETRY('POINT'),
		defaultValue: null
	},
	facebook_token: {
		type: DataTypes.STRING
	},
	socket_id: {
		type: DataTypes.STRING
	},
	stripe_customer_id: {
		type: DataTypes.STRING
	},
	stripe_customer: {
		type: DataTypes.JSON
	},
	stripe_connect_account_id: {
		type: DataTypes.STRING
	},
	ephemeral_key: {
		type: DataTypes.JSON
	},
	read_receipt: {
		type: DataTypes.BOOLEAN,
		defaultValue: false
	},
	translation_services: {
		type: DataTypes.BOOLEAN,
		defaultValue: true
	}
},
	{
		validate: {
			notACelebrityName() {
				const fullName = `${this.first_name}${this.last_name}`
					.toLowerCase()
					.trim()

				if (celebHashMap[fullName])
					throw new Error(`The name ${this.first_name} ${this.last_name} is a celebrity's name and cannot be a user's name unless approved by 8`)
			}
		},

		scopes: {
			verified: {
				where: {
					verified: true
				}
			},
			unverified: {
				where: {
					verified: false
				}
			}
		},

	},
	{
		paranoid: true
	},
)

return user
`

Sequelize provides a validate option that you can use to validate the attribute values passed into your models.

You can validate individual attributes or the whole model depending on how you define the validate option.

Let’s see an example of validating attributes in Sequelize.

Suppose you have a Users table with two columns: firstName and email.

CREATE TABLE `Users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `firstName` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

When defining the model for the table, you can pass the validate option to any of your attributes that requires validation.

To validate the email field, you can use the provided isEmail validator as follows:

const User = sequelize.define(
  "User",
  {
    firstName: Sequelize.STRING,
    email: {
      type: Sequelize.STRING,
      validate: { isEmail: true },
    },
  },
  { timestamps: false }
);

By adding the isEmail validation, Sequelize will throw an error when the email value you pass fails the validation check.

For example, when inserting a new row using the create() method as follows:

const response = await User.create({
  firstName: "Jack",
  email: "jack", // Error: Validation isEmail on email failed
});

Because the email value above isn’t a valid email address, Sequelize will throw an error and stop your code execution.

You need to add a try..catch block around the method call to gracefully handle Sequelize validation error.

You can add a validate option to any of your model attributes.

Here’s how to add length validation to the firstName attribute:

const User = sequelize.define(
  "User",
  {
    firstName: {
      type: Sequelize.STRING,
      validate: { len: 5 },
    },
    email: {
      type: Sequelize.STRING,
      validate: { isEmail: true },
    },
  },
  { timestamps: false }
);

The len validation property above will validate that the firstName attribute length is 5 or greater.

You can also set a range of minimum and maximum length for the len validation as follows:

validate: {
  len: [5, 10];
}

Now the attribute length must be between 5 and 10.

Sequelize custom validators

Sequelize provides many built-in validators that you can use in your validate option.

The len and isEmail are two of these built-in validators.

All available validators are listed on Sequelize validation documentation.

When the built-in validators are not sufficient for your project, you can even create a custom validator by passing a function.

For example, here’s a custom validator to check the length of the firstName attribute:

const User = sequelize.define(
  "User",
  {
    firstName: {
      type: Sequelize.STRING,
      validate: {
        checkLength(value) {
          if (value.length < 7) {
            throw new Error("Length must be 7 or greater!");
          }
        },
      },
    },
  },
  { timestamps: false }
);

And that’s how you create a custom validation using Sequelize.

Sequelize validation on the model level

All validations you see above are created on the attributes level.

Sequelize also allows you to write validations on the model level by passing the validate option to the model (inside the define() method call)

Here’s an example of a model level validation:

const User = sequelize.define(
  "User",
  {
    firstName: Sequelize.STRING,
    email: Sequelize.STRING,
  },
  {
    timestamps: false,
    validate: {
      userValidation() {
        if (this.firstName.length < 7) {
          throw new Error("firstName length must be 7 or greater!");
        }
        if (this.email.includes("@mail.com")) {
          throw new Error("Email must not use mail.com address!");
        }
      },
    },
  }
);

The userValidation() function above is defined on the model level. You can use any name for the custom function.

When validating at the model level, the this keyword refers to the model instance created when you call the create() method.

The attributes for the model are available as properties of the this keyword as shown in the example above.

Inside the validation function, you can define as many or as few conditions as you require for the model.

Validating bulkCreate function

By default, Sequelize will turn off the validations for the bulkCreate() function.

When you need to validate a bulkCreate() method call, you need to pass the validate: true option to the method:

await User.bulkCreate(
  [
    {
      firstName: "Jack",
      email: "jack@mail.com",
    },
    {
      firstName: "Susan",
      email: "susan",
    },
  ],
  { validate: true }
);

And that’s how you enable validation for the bulkCreate() method.

Now you’ve learned how to validate values passed into Sequelize models and attributes. Nice work! 👍

For more information on Sequelize validation, you can refer to the Sequelize validations and constraints documentation.

Validations & Constraints

In this tutorial you will learn how to setup validations and constraints for your models in Sequelize.

For this tutorial, the following setup will be assumed:

const { Sequelize, Op, Model, DataTypes } = require("sequelize");
const sequelize = new Sequelize("sqlite::memory:");

const User = sequelize.define("user", {
  username: {
    type: DataTypes.TEXT,
    allowNull: false,
    unique: true
  },
  hashedPassword: {
    type: DataTypes.STRING(64),
    validate: {
      is: /^[0-9a-f]{64}$/i
    }
  }
});

(async () => {
  await sequelize.sync({ force: true });
  
})();

Difference between Validations and Constraints​

Validations are checks performed in the Sequelize level, in pure JavaScript. They can be arbitrarily complex if you provide a custom validator function, or can be one of the built-in validators offered by Sequelize. If a validation fails, no SQL query will be sent to the database at all.

On the other hand, constraints are rules defined at SQL level. The most basic example of constraint is an Unique Constraint. If a constraint check fails, an error will be thrown by the database and Sequelize will forward this error to JavaScript (in this example, throwing a SequelizeUniqueConstraintError). Note that in this case, the SQL query was performed, unlike the case for validations.

Unique Constraint​

Our code example above defines a unique constraint on the username field:

/* ... */ {
  username: {
    type: DataTypes.TEXT,
    allowNull: false,
    unique: true
  },
} /* ... */

When this model is synchronized (by calling sequelize.sync for example), the username field will be created in the table as `username` TEXT UNIQUE, and an attempt to insert an username that already exists there will throw a SequelizeUniqueConstraintError.

Allowing/disallowing null values​

By default, null is an allowed value for every column of a model. This can be disabled setting the allowNull: false option for a column, as it was done in the username field from our code example:

/* ... */ {
  username: {
    type: DataTypes.TEXT,
    allowNull: false,
    unique: true
  },
} /* ... */

Without allowNull: false, the call User.create({}) would work.

Note about allowNull implementation​

The allowNull check is the only check in Sequelize that is a mix of a validation and a constraint in the senses described at the beginning of this tutorial. This is because:

  • If an attempt is made to set null to a field that does not allow null, a ValidationError will be thrown without any SQL query being performed.
  • In addition, after sequelize.sync, the column that has allowNull: false will be defined with a NOT NULL SQL constraint. This way, direct SQL queries that attempt to set the value to null will also fail.

Validators​

Model validators allow you to specify format/content/inheritance validations for each attribute of the model. Validations are automatically run on create, update and save. You can also call validate() to manually validate an instance.

Per-attribute validations​

You can define your custom validators or use several built-in validators, implemented by validator.js (10.11.0), as shown below.

sequelize.define('foo', {
  bar: {
    type: DataTypes.STRING,
    validate: {
      is: /^[a-z]+$/i,          
      is: ["^[a-z]+$",'i'],     
      not: /^[a-z]+$/i,         
      not: ["^[a-z]+$",'i'],    
      isEmail: true,            
      isUrl: true,              
      isIP: true,               
      isIPv4: true,             
      isIPv6: true,             
      isAlpha: true,            
      isAlphanumeric: true,     
      isNumeric: true,          
      isInt: true,              
      isFloat: true,            
      isDecimal: true,          
      isLowercase: true,        
      isUppercase: true,        
      notNull: true,            
      isNull: true,             
      notEmpty: true,           
      equals: 'specific value', 
      contains: 'foo',          
      notIn: [['foo', 'bar']],  
      isIn: [['foo', 'bar']],   
      notContains: 'bar',       
      len: [2,10],              
      isUUID: 4,                
      isDate: true,             
      isAfter: "2011-11-05",    
      isBefore: "2011-11-05",   
      max: 23,                  
      min: 23,                  
      isCreditCard: true,       

      
      isEven(value) {
        if (parseInt(value) % 2 !== 0) {
          throw new Error('Only even values are allowed!');
        }
      }
      isGreaterThanOtherField(value) {
        if (parseInt(value) <= parseInt(this.otherField)) {
          throw new Error('Bar must be greater than otherField.');
        }
      }
    }
  }
});

Note that where multiple arguments need to be passed to the built-in validation functions, the arguments to be passed must be in an array. But if a single array argument is to be passed, for instance an array of acceptable strings for isIn, this will be interpreted as multiple string arguments instead of one array argument. To work around this pass a single-length array of arguments, such as [['foo', 'bar']] as shown above.

To use a custom error message instead of that provided by validator.js, use an object instead of the plain value or array of arguments, for example a validator which needs no argument can be given a custom message with

isInt: {
  msg: "Must be an integer number of pennies"
}

or if arguments need to also be passed add an args property:

isIn: {
  args: [['en', 'zh']],
  msg: "Must be English or Chinese"
}

When using custom validator functions the error message will be whatever message the thrown Error object holds.

See the validator.js project for more details on the built in validation methods.

Hint: You can also define a custom function for the logging part. Just pass a function. The first parameter will be the string that is logged.

allowNull interaction with other validators​

If a particular field of a model is set to not allow null (with allowNull: false) and that value has been set to null, all validators will be skipped and a ValidationError will be thrown.

On the other hand, if it is set to allow null (with allowNull: true) and that value has been set to null, only the built-in validators will be skipped, while the custom validators will still run.

This means you can, for instance, have a string field which validates its length to be between 5 and 10 characters, but which also allows null (since the length validator will be skipped automatically when the value is null):

class User extends Model {}
User.init({
  username: {
    type: DataTypes.STRING,
    allowNull: true,
    validate: {
      len: [5, 10]
    }
  }
}, { sequelize });

You also can conditionally allow null values, with a custom validator, since it won’t be skipped:

class User extends Model {}
User.init({
  age: Sequelize.INTEGER,
  name: {
    type: DataTypes.STRING,
    allowNull: true,
    validate: {
      customValidator(value) {
        if (value === null && this.age !== 10) {
          throw new Error("name can't be null unless age is 10");
        }
      }
    }
  }
}, { sequelize });

You can customize allowNull error message by setting the notNull validator:

class User extends Model {}
User.init({
  name: {
    type: DataTypes.STRING,
    allowNull: false,
    validate: {
      notNull: {
        msg: 'Please enter your name'
      }
    }
  }
}, { sequelize });

Model-wide validations​

Validations can also be defined to check the model after the field-specific validators. Using this you could, for example, ensure either neither of latitude and longitude are set or both, and fail if one but not the other is set.

Model validator methods are called with the model object’s context and are deemed to fail if they throw an error, otherwise pass. This is just the same as with custom field-specific validators.

Any error messages collected are put in the validation result object alongside the field validation errors, with keys named after the failed validation method’s key in the validate option object. Even though there can only be one error message for each model validation method at any one time, it is presented as a single string error in an array, to maximize consistency with the field errors.

An example:

class Place extends Model {}
Place.init({
  name: Sequelize.STRING,
  address: Sequelize.STRING,
  latitude: {
    type: DataTypes.INTEGER,
    validate: {
      min: -90,
      max: 90
    }
  },
  longitude: {
    type: DataTypes.INTEGER,
    validate: {
      min: -180,
      max: 180
    }
  },
}, {
  sequelize,
  validate: {
    bothCoordsOrNone() {
      if ((this.latitude === null) !== (this.longitude === null)) {
        throw new Error('Either both latitude and longitude, or neither!');
      }
    }
  }
})

In this simple case an object fails validation if either latitude or longitude is given, but not both. If we try to build one with an out-of-range latitude and no longitude, somePlace.validate() might return:

{
  'latitude': ['Invalid number: latitude'],
  'bothCoordsOrNone': ['Either both latitude and longitude, or neither!']
}

Such validation could have also been done with a custom validator defined on a single attribute (such as the latitude attribute, by checking (value === null) !== (this.longitude === null)), but the model-wide validation approach is cleaner.


Sequelize

6.23

  • Paranoid

    Sequelize supports the concept of paranoid tables.

  • Raw Queries

    As there are often use cases in which it is just easier to execute raw already prepared SQL queries, you can sequelize.query method.

  • Function

    format(arr: unknown[], dialect: AbstractDialect): formatNamedParameters(sql: string, object, dialect: AbstractDialect): injectReplacements(sqlString: dialect:

  • Getting Started

    In this tutorial you will learn make simple setup of Sequelize.

We’re getting the sequelized validation
error messages back from Sequelize.
0:00

And this response, we’re seeing
the default error messages provided for
0:04

each validation error item.
0:09

Let’s instead display clear and
more useful custom error messages.
0:11

Sequalize offers several built-in
validators that allow you to specify
0:16

validations for each attribute of the
model as well as custom error messages.
0:20

To begin using them, add a validate object
inside a models attribute object like so.
0:25

The notNull validator allows you to
customize the allowNull false error
0:34

message.
0:39

Inside this new object,
I’ll add the message property and
0:40

set it to my custom error message.
0:44

A name is required.
0:47

I’ll add a similar custom
error message for email.
0:53

And birthday, and password.
1:10

I’ll test these updates over in
Postman by once again sending a POST
1:25

request with an empty object.
1:29

Now the custom error messages
display in the response body.
1:33

Keep in mind that the notNull validator is
1:37

only allowed with
allowingNull set to false.
1:43

So when using notNull,
1:46

you must also specify allowNull false
in the model attribute’s object.
1:48

Since the name, email and
password values are string data types and
1:55

birthday is date only, we’re currently
able to set their value to an empty or
1:59

blank string and
it will be successfully validated.
2:04

Which means that the user’s name, email or
2:07

even password would be
missing from the data.
2:10

So next I’ll use the notEmpty
validator to ensure that users cannot
2:13

create a new account if they
submit empty values or fields.
2:18

Starting with the name attribute,
I’ll set a custom error message when
2:23

validation fails by setting notEmpty
to an object containing a message
2:28

property set to the custom message,
Please provide a name.
2:33

I’ll do the same for birthday.
2:43

Then password.
2:51

For the email attribute,
3:04

I’ll use the isEmail validator
to check the email format.
3:06

If the submitted email format is not for
3:11

example, user@website.com Sequelize
will throw a validation error.
3:14

I’ll add the message property to
display a custom error message,
3:19

Please provide a valid email address.
3:23

All right now I’m ready to
test my updates in Postman.
3:30

First, I’ll test the post
request by setting the name,
3:34

birthday and password values in
the body to an empty string.
3:37

Then set the email value to
an invalid format, like guil.com.
3:41

Click Send and
receive a 400 Bad Request status.
3:49

Notice the errors arrays and the response
containing the custom error messages.
3:53

Next, I’ll set each
property to a valid value.
4:00

Click Send and
now I receive a 201 Created status,
4:06

which means that the user entry
was successfully created and
4:10

stored in the database as you
see here in the response.
4:14

Finally I’ll send a get request
to the API users route.
4:17

Remember that this route
here in routes.js,
4:22

the handler calls User.findAll to retrieve
all entries from the user’s table.
4:26

I receive a 200 OK status.
4:34

And in the response body,
I see an array with the new user object.
4:37

It has an id of 1, along with
the createdAt and updatedAt timestamps.
4:41

Sequelize adds to every model by default.
4:47

Good.
4:50

Понравилась статья? Поделить с друзьями:
  • Sentry mode has turned off due to a sentry system error
  • Sentry is attempting to send 2 pending error messages
  • Sentinel runtime environment installer error
  • Sentinel rms development kit error 93 the given license code is already added
  • Sentinel hasp run time installation error