How to exclude entity field from returned by controller JSON. NestJS + Typeorm
I'd suggest creating an interceptor that takes advantage of the class-transformer library:
@Injectable()export class TransformInterceptor implements NestInterceptor { intercept( context: ExecutionContext, call$: Observable<any>, ): Observable<any> { return call$.pipe(map(data => classToPlain(data))); }}
Then, simply exclude properties using @Exclude()
decorator, for example:
import { Exclude } from 'class-transformer';export class User { id: number; email: string; @Exclude() password: string;}
You can overwrite the toJSON method of the model like this.
@Entity()export class User extends BaseAbstractEntity implements IUser { static passwordMinLength: number = 7; @ApiModelProperty({ example: faker.internet.email() }) @IsEmail() @Column({ unique: true }) email: string; @IsOptional() @IsString() @MinLength(User.passwordMinLength) @Exclude({ toPlainOnly: true }) @Column({ select: false }) password: string; @IsOptional() @IsString() @Exclude({ toPlainOnly: true }) @Column({ select: false }) passwordSalt: string; toJSON() { return classToPlain(this); } validatePassword(password: string) { if (!this.password || !this.passwordSalt) { return false; } return comparedToHashed(password, this.password, this.passwordSalt); }}
By using the class-transformer method of plainToClass along with the @Exclude({ toPlainOnly: true }), the password will be excluded from the JSON response, but will be available in the model instance. I like this solution because it keeps all the model configuration in the entity.
As an addition to Kamil's answer:
Instead of creating your own interceptor, you can now use the built-in ClassSerializerInterceptor
, see the serialization docs.
@UseInterceptors(ClassSerializerInterceptor)
You can use it on a controller class or its individual methods. Each entity returned by such a method will be transformed with class-transformer and hence take the @Exclude
annotations into account:
import { Exclude } from 'class-transformer';export class User { /** other properties */ @Exclude() password: string;}
You can customize its behavior by defining @SerializeOptions()
on your controller or its methods:
@SerializeOptions({ excludePrefixes: ['_'], groups: ['admin']})
to, for example, expose certain fields only to certain users:
@Expose({ groups: ["admin"] })adminInfo: string;