Custom validator via class-validator has null pointer

71 views Asked by At

I have this:

    import * as val from 'class-validator';
    import {ObjectId as MongoId} from 'mongodb';
    
    @val.ValidatorConstraint({async: false})
    export class IsTraceValidConstraint implements val.ValidatorConstraintInterface {
      validate(trace: any, args: val.ValidationArguments) { 
        return trace.deviceId && typeof trace.deviceId === 'string'; // << trace is undefined
      }
    
      defaultMessage(args: val.ValidationArguments) {
        return 'Trace validation failed';
      }
    }
    
    // Function to create the class-level decorator
    export function IsTraceValid(validationOptions?: val.ValidationOptions) {
      return function (target: Function) {
        val.registerDecorator({
          target: target,
          options: validationOptions,
          constraints: [],
          validator: IsTraceValidConstraint,
          name: 'isTraceValid',
          propertyName: 'isTraceValid',
        });
      };
    }

then I use it like so:

    @IsTraceValid()
    @t.Unique("user-hash-device", ["hash", "userId", "deviceId"])
    @t.Entity('vibe_trace')
    export class Trace extends From<Trace> { }

but if I run it, I get a null pointer -

trace is undefined in validate callback - so trace.deviceId throws an error

Clearly I am doing something wrong - but what?

1

There are 1 answers

4
Andrew Gillis On BEST ANSWER

Update propertyName in your decorator registration to match the name of the property you want to validate in your custom constraint. i.e. 'deviceId'.

In your custom constraint you now check directly against that value in your validate method. If you want to check against other properties you can access the trace instance via args.object

import * as val from 'class-validator';
import { ObjectId as MongoId } from 'mongodb';

@val.ValidatorConstraint({ async: false })
export class IsTraceValidConstraint implements val.ValidatorConstraintInterface {
  validate(value: any, args: val.ValidationArguments) {
    // trace instance is accessible via `args.object`
    return typeof value === 'string';
  }

  defaultMessage(args: val.ValidationArguments) {
    return 'Trace validation failed';
  }
}

// Function to create the class-level decorator
export function IsTraceValid(validationOptions?: val.ValidationOptions) {
  return function (target: Function) {
    val.registerDecorator({
      target: target,
      options: validationOptions,
      constraints: [],
      validator: IsTraceValidConstraint,
      name: 'isTraceValid',
      propertyName: 'deviceId',
    });
  };
}