Vue 3 and Validation with the Class-Validator
Tags: vue, validation, typescript
Published: 2020-08-19 10:59:02

---
title: Vue 3 and Validation with the Class-Validator
published: true
date: 2020-08-16 20:35:22 UTC
tags: Vue,Validation,TypeScript
canonical_url: http://wildermuth.com/2020/08/16/Vue-3-and-Validation-with-Class-Validation
---

![Validation](https://wilderminds.blob.core.windows.net/img/validation.png)I've been working with Vue 3 Beta and RC (currently in RC5) and early on I needed some validation but the Vue stalwards of _vuelidate_ and _vee-validate_ weren't working with the Composition API early on. What was I do to?

After some searching I ran into _class-validator_ library. It got me thinking about how to separate the validation from the UI like I usually do in the server.

I thought I'd run you though a little example. If you want to take a look at the project, I have an example on GitHub with tags for before and after:

> [https://github.com/shawnwildermuth/vueclassvalidation/tags](https://github.com/shawnwildermuth/vueclassvalidation/tags)

Let's get started, first let's look at the _class-validator_ library. For example, I have a model that my project uses that looks like this:

```
export default class Customer {
  id = 0;
  fullName: string | undefined;
  firstName: string | undefined;
  lastName: string | undefined;
  phoneNumber: string | undefined;
  companyName: string | undefined;
  addressLine1: string | undefined;
  addressLine2: string | undefined;
  addressLine3: string | undefined;
  cityTown: string | undefined;
  stateProvince: string | undefined;
  postalCode: string | undefined;
}

```

To use this, I have to make sure that the TypeScript configuration (tsconfig.json) supports decorators:

```
{
  "compilerOptions": {
...
    "experimentalDecorators": true,
...

```

I brought in the library by:

```
> npm install class-validator --save

```

After importing the decorators I applied some validations:

```
export default class Customer {
  id = 0;
  fullName: string | undefined;

  @MinLength(3, {
    message: "Must be > 3 characters"
  })
  firstName: string | undefined;

  @MinLength(5, {
    message: "Must be > 5 characters"
  })
  lastName: string | undefined;

  @IsOptional()
  @IsPhoneNumber("US", { message: "Must be a valid phone number" })
  phoneNumber: string | undefined;

  @IsOptional()
  @MinLength(5, {
    message: "Must be > 5 characters"
  })
  companyName: string | undefined;

  @IsDefined({
    message: "Address is required"
  })
  addressLine1: string | undefined;

  addressLine2: string | undefined;
  addressLine3: string | undefined;

  @IsDefined({
    message: "City is required"
  })
  cityTown: string | undefined;

  @IsDefined({
    message: "State is required"
  })
  @Length(2, 2, {
    message: "Must be a US State"
  })
  stateProvince: string | undefined;

  @IsDefined({
    message: "Zipcode is required"
  })
  @Matches(/^[0-9]{5}(?:-[0-9]{4})?$/, {
    message: "Must be valid Zipcode"
  })
  postalCode: string | undefined;

}

```

The decorators feel a lot like .NET validation. What I really like is that it's not a plugin for Vue so similar code could be used in different platforms or even in Node.

The class-validation library has a fairly simple function called validate that takes the object to validate and return a set of errors if validation fails.

```
let result = await validate(someObj);
for(const error of result) {
    // ...
}

```

To use this, I decided to make a base class for the model to check the validation on any of the models:

```
import { validate, ValidationError } from "class-validator";

export default abstract class BaseModel {

  public errors: Object;

  constructor() {
    this.errors = {};
  }

  public get isValid(): boolean {
    return Object.keys(this.errors).length === 0;
  }

  public async validateModel() {
    let result = await validate(this);
    this.errors = this.setError(result)
  }

  private setError(result: ValidationError[]): Object {
    let propBag = {};

    for (const error of result) {
      for (const key in error.constraints) {
        if (Object.prototype.hasOwnProperty.call(error.constraints, key)) {
           const msg = error.constraints[key];
          (propBag as any)[error.property] = msg;
        }
      } 
    }

    return propBag; 
  }
}

```

This way in the view I can simply bind to the errors collection:

```
    <div class="form-group">
      <label for="firstName">First Name</label>
      <input class="form-control" name="firstName" v-model="customer.firstName" />
      <span
        v-if="customer.errors.firstName"
        class="text-danger small p-0 m-0"
      >{{ customer.errors.firstName }}</span>
    </div>

```

This snippet shows that I'm binding to the errors collection where I'd have a property per field that has an error. I flatten the errors collection a bit in the base class (see the setError function).

In this way the rules are no longer in the UI but should match the server-validation.

Any ideas on how to improve this?

[![Creative Commons License](http://i.creativecommons.org/l/by-nc-nd/3.0/88x31.png)](http://creativecommons.org/licenses/by-nc-nd/3.0/)

          This work by [Shawn Wildermuth](http://wildermuth.com) is licensed under a [Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License](http://creativecommons.org/licenses/by-nc-nd/3.0/).  
          Based on a work at [wildermuth.com](http://wildermuth.com).

* * *

If you liked this article, see Shawn's courses on [Pluralsight](http://shawnw.me/pscourses).
 ![](http://feeds.feedburner.com/~r/ShawnWildermuth/~4/S9XpzACl0po)