Class-transformer: class transformer not stripping additional properties

Created on 17 Jul 2017  路  10Comments  路  Source: typestack/class-transformer

Refer to following for details:

https://github.com/pleerock/routing-controllers/issues/200

All validation libraries like Joi, ajv, validate.js support stripping of properties which are not part of the schema, so this can be supported as a decorator similar to @Exclude().

As suggested by @NoNameProvided

The solution would be to add a @StictEquals or similar class decorator to allow only the selected fields and throw otherwise, and a @Equals to simply strip down the unknown properties.

transformations donreleased feature

Most helpful comment

Since it's not possible to know the properties of a class unless they are initialized, having a decorator is must to know the field names. In many, cases most of the fields do have some decorator say for validation or any other purpose. It should be possible to strip non-decorated properties if present in input object, that way adding Expose() to all the properties can be avoided unless a property doesn't have any other decorator from class-validator. e.g.

export class RoleViewModel {

    @IsNotEmpty()
    @MaxLength(256)
    name: string;

    @MaxLength(256)
    description: string;

    @IsArray()
    @ArrayUnique()
    claims: string[];
}

will strip any other property other than the decorated ones if allowDecoratedPropertiesOnly is set. This may perhaps require class-validator decorators to have tight integration with class-transformer.

If you like the idea, I would love giving it a try and submit a PR.

All 10 comments

Since it's not possible to know the properties of a class unless they are initialized, having a decorator is must to know the field names. In many, cases most of the fields do have some decorator say for validation or any other purpose. It should be possible to strip non-decorated properties if present in input object, that way adding Expose() to all the properties can be avoided unless a property doesn't have any other decorator from class-validator. e.g.

export class RoleViewModel {

    @IsNotEmpty()
    @MaxLength(256)
    name: string;

    @MaxLength(256)
    description: string;

    @IsArray()
    @ArrayUnique()
    claims: string[];
}

will strip any other property other than the decorated ones if allowDecoratedPropertiesOnly is set. This may perhaps require class-validator decorators to have tight integration with class-transformer.

If you like the idea, I would love giving it a try and submit a PR.

Would use that. +1

It was always confusing to me, why class-transfomer is allowing other properties, than those specified in object class, to come through? They're not part of the class, they should be out. If anything, you can even compare by property name. Is there a limitation here? Am I missing some option switch?

This is now implemented in class-validator.

Hi ! Sorry to bother, but how is this implemented / how to use this ? (and if it is implemented, maybe let's close the issue ?)

As NoNameProvided said it is implemented in class-validator, so it can be closed.

How it works is described here: https://github.com/typestack/class-validator/blob/master/README.md#whitelisting

Although, I think that whitelisting of properties is not something class validator should do, it should be rather implemented in class sanitizer

Yeah, it doesn't seem like a task for a validator. Validator, by definition, doesn't modify anything. I think it should be ported to class-transformer.

Now we have excludeExtraneousValues in https://github.com/typestack/class-transformer/issues/198, but I don't think its the proper solution. Mainly, because it uses a decorator that was meant for something else, really. This creates an unfortunate side effect. When all properties are exposed, class-transformer will set them to undefined (if there's no value in source object, when converting from plain object). I really think you should use a new decorator for this, one that doesn't have any additional functionality other than making property available for reflection.

As it was mentioned to know what properties a class has we have to add at least one decorator to it. The desired behavior is now implemented via a mix of @Exclude, @Expose decorator, and the excludeExtraneousValues option. You can use something like this:

class MyClass {
  @Expose()
  public propertyOne!: string;

  @Expose()
  public propertyTwo!: string;
}

const instance = plainToClass(MyClass, {
  propertyOne: 'some-allowed-value',
  propertyTwo: 'some-allowed-value',
  notAllowedVaue: 'bad',
}, { excludeExtraneousValues: true });

console.log(instance);
// returns MyClass { propertyOne: 'some-allowed-value', propertyTwo: 'some-allowed-value' }

Also one can still use the originally offered solution: excluding everything and exposing properties explicitly:

import 'reflect-metadata';
import { Expose, Exclude, plainToClass } from './index';

@Exclude()
class MyClass {
  @Expose()
  public propertyOne!: string;

  @Expose()
  public propertyTwo!: string;
}

const instance = plainToClass(MyClass, {
  propertyOne: 'some-allowed-value',
  propertyTwo: 'some-allowed-value',
  notAllowedVaue: 'bad',
});

console.log(instance);
// returns MyClass { propertyOne: 'some-allowed-value', propertyTwo: 'some-allowed-value' }

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings