Using JavaScript classes to model and validate data

Updated: March 20, 2023 By: Wolf Post a comment

JavaScript classes are a way of defining and creating objects with properties and methods. You can use JavaScript classes to model and validate data by defining the data structure, validation rules, and methods inside the class.

A Simple Example

This minimal example helps you understand the basic concepts of using classes to model and validate data.

Modeling Data

To use a class to model data, you first need to define the class. In the class definition, you can define properties and methods that will be available on instances of the class. Here’s an example of a class definition for a Person:

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

To create an instance of the Person class (a Person object), you can use the new keyword:

const person = new Person('Wolf', 35);
person.greet(); 
// Hello, my name is Wolf and I am 35 years old.

Validating Data

You can add validation logic to the constructor method of your class.

Example:

class Person {
  constructor(name, age) {
    if (typeof name !== 'string') {
      throw new Error('Name must be a string.');
    }

    if (typeof age !== 'number') {
      throw new Error('Age must be a number.');
    }

    if (age < 0 || age > 120) {
      throw new Error('Age must be between 0 and 120.');
    }

    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

Let’s try to create some Person objects and see how our validation logic works:

// Valid Person
const person1 = new Person('Wolf', 35);
person1.greet(); 
// Hello, my name is Wolf and I am 35 years old.

// Invalid Person - Name not a string
try {
  const person2 = new Person(123, 30);
  person2.greet();
} catch (error) {
  console.log(error.message); 
  // Name must be a string.
}

// Invalid Person - Age not a number
try {
  const person3 = new Person('Puppy', '30');
  person3.greet();
} catch (error) {
  console.log(error.message); 
  // Age must be a number.
}

// Invalid Person - Age not in range
try {
  const person4 = new Person('Demon of Hatred', 150);
  person4.greet();
} catch (error) {
  console.log(error.message); 
  // Age must be between 0 and 120.
}

An Advanced Example

The previous example is just a prelude. Let’s write code for a more realistic and complex use case. We will use regular expressions to validate data.

In this example, we will define a User class, which is used for creating and validating user objects with properties like name, email, and password. It can be useful for implementing authentication and authorization features in a web application. For example, you could use the User class to create a new user with some input data, check if the user data is valid, and store the user in a database or session.

The code with explanations:

// Define User class
class User {
  // Constructor takes an object of user data
  constructor(userData) {
    // Assign properties from user data
    this.name = userData.name;
    this.email = userData.email;
    this.password = userData.password;
    this.passwordConfirmation = userData.passwordConfirmation;

    // Define validation errors as an empty object
    this.errors = {};
  }

  // Method to check if user data is valid
  isValid() {
    // Reset errors object
    this.errors = {};

    // Check if name is present and a string
    if (!this.name || typeof this.name !== 'string') {
      this.errors.name = 'Name is required';
    }

    // Check if name length is between 3 and 20 characters (inclusive)
    else if (this.name.length < 3 || this.name.length > 20) {
      this.errors.name = 'Name must be between 3 and 20 characters long';
    }

    // Check if email is present and a string
    if (!this.email || typeof this.email !== 'string') {
      this.errors.email = 'Email is required';
    }

    // Check if email matches a valid email format using a regular expression
    else if (!/^[^@]+@[^@]+\.[^@]+$/.test(this.email)) {
      this.errors.email = 'Email must be a valid email address';
    }

    // Check if password is present and a string
    if (!this.password || typeof this.password !== 'string') {
      this.errors.password = 'Password is required';
    }

    // Check if password length is at least 8 characters long
    else if (this.password.length < 8) {
      this.errors.password = 'Password must be at least 8 characters long';
    }

    // Check if password confirmation matches password
    else if (this.password !== this.passwordConfirmation) {
      this.errors.passwordConfirmation = 'Password confirmation does not match';
    }

    // Return true if errors object is empty, false otherwise
    return Object.keys(this.errors).length === 0;
  }

  // Method to get validation errors
  getErrors() {
    return this.errors;
  }
}

Let’s see how our class deals with invalid inputs:

// Create a user instance with some sample data
let user = new User({
  name: '',
  email: 'wolf@slingacademycom',
  password: 'secret1234',
  passwordConfirmation: 12345678,
});

// Check if user is valid
if (user.isValid()) {
  console.log('User is valid');
} else {
  console.log('User is invalid');
}

// Get validation errors (if any)
let errors = user.getErrors();
if(Object.keys(errors).length > 0){
    console.log(errors);
}

Output:

User is invalid
{
  name: 'Name is required',
  email: 'Email must be a valid email address',
  passwordConfirmation: 'Password confirmation does not match'
}

Now try to provide valid data:

// Create a user instance with some sample data
let user = new User({
  name: 'Wolf',
  email: '[email protected]',
  password: 'secret1234',
  passwordConfirmation: 'secret1234',
});

// Check if user is valid
if (user.isValid()) {
  console.log('User is valid');
} else {
  console.log('User is invalid');
}

// Get validation errors (if any)
let errors = user.getErrors();
if (Object.keys(errors).length > 0) {
  console.log(errors);
}

Output:

User is valid

The trade-offs

Using classes for modeling and validating data is a matter of personal choice and trade-offs. There is no definitive answer to whether it is good or not to use JavaScript classes to model and validate data. It depends on your preferences, project requirements, and coding style.

Advantages:

  • Classes provide a clear and consistent way of defining and creating objects with properties and methods.
  • Classes make it easier to reuse code and implement inheritance and polymorphism.
  • Classes can help organize your code into modules and namespaces.

Disadvantages:

  • Classes add some syntactic overhead and complexity to your code.
  • Classes may not be compatible with older browsers or environments that do not support ES6 features.

I hope this helps. Happy coding & have a nice day!