序列化:如何排除 json 响应中的实体列,但不排除 Nestjs 中的内部查询
Posted
技术标签:
【中文标题】序列化:如何排除 json 响应中的实体列,但不排除 Nestjs 中的内部查询【英文标题】:Serialization: How to exclude Entity columns in json response but not internal queries in Nestjs 【发布时间】:2019-06-17 02:54:39 【问题描述】:编辑:我已经看过这个问题/答案How to exclude entity field from controller json 但是,如下所述 - 这是从所有查询中排除该字段(到尝试处理用户验证时,使用 findOne 存储库查询排除在没有 ClassSerializerInterceptor 的路由/控制器方法上的密码字段
我在 nest.js / typeorm 中有一个实体;我试图从返回的 json 中排除密码字段,但不从我的服务中的任何存储库查询中排除密码字段。例如:
user.entity.ts
:
import Entity, Column, PrimaryGeneratedColumn, CreateDateColumn,
UpdateDateColumn, ManyToOne from 'typeorm';
import Exclude from 'class-transformer';
import Account from '../accounts/account.entity';
@Entity()
export class User
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
firstName: string;
@Column()
lastName: string;
@Column(
unique: true,
)
email: string;
@Column()
password: string;
auth.controller.ts
:
import Controller, Post, Body, Request, Req, Get, UseInterceptors, ClassSerializerInterceptor, UseGuards from '@nestjs/common';
import AuthGuard from '@nestjs/passport';
import AuthService from './auth.service';
import IUserRequest from '../../interfaces/user-request.interface';
@Controller('auth')
export class AuthController
constructor(private readonly authService: AuthService)
@Post('/login')
async login(@Request() req: Request)
const user = await this.authService.checkCredentials(req.body);
return this.authService.logUserIn(user.id);
@Get('/profile')
@UseGuards(AuthGuard())
@UseInterceptors(ClassSerializerInterceptor)
async profile(@Request() req: IUserRequest)
const profile = await this.authService.getLoggedInProfile(req.user.id);
return profile ;
如果我像这样在密码中添加Exclude()
@Exclude()
@Column()
password: string;
密码包含在响应中
如果我从密码中删除Column()
,
@Exclude()
password: string;
密码被排除在响应之外和所有内部查询,例如:
const user = await this.userRepository.findOne( where: id , relations: ['account']);
在nest.js 中使用ClassSerializerInterceptor
是否可行?
如果是这样,将不胜感激指向正确方向的指针。
【问题讨论】:
【参考方案1】:您可以跳过属性depending on the operation。在您的情况下,您将使用:
@Column()
@Exclude( toPlainOnly: true )
password: string;
这意味着,仅当类转换为 json 时(当您发送响应时)而不是当 json 转换为类时(当您收到请求时)才跳过密码。
然后将@UseInterceptors(ClassSerializerInterceptor)
添加到您的控制器或控制器方法中。这将在您返回实体类时自动将其转换为 json。
要使ClassSerializerInterceptor
正常工作,请确保您的实体首先转换为类。这可以通过使用带有 transform: true
选项的ValidationPipe
或通过从存储库(数据库)返回实体来自动完成。此外,您必须返回实体本身:
@Post()
@UseInterceptors(ClassSerializerInterceptor)
addUser(@Body(new ValidationPipe(transform: true)) user: User)
// Logs user with password
console.log(user);
// Returns user as JSON without password
return user;
否则,你必须手动转换它:
async profile(@Request() req: IUserRequest)
// Profile comes from the database so it will be an entity class instance already
const profile = await this.authService.getLoggedInProfile(req.user.id);
// Since we are not returning the entity directly, we have to transform it manually
return profile: plainToClass(profile) ;
【讨论】:
感谢您的回答。不幸的是,由于某种原因,这仍然不适用于@UseInterceptors(ClassSerializerInterceptor)。但是,添加类转换 @TransformClassToPlain() 就可以了 啊,我只是看到你没有直接返回实体。ClassSerializerInterceptor
仅在返回实体本身时才有效,因此 return profile
而不是 return profile
。如果你不直接返回它,你必须使用plainToClass()
手动转换它。【参考方案2】:
建议也看看TypeOrm hidden-columns
在这里,您的密码列上有@Column(select: false)
,所有使用标准查找或查询的请求都将排除密码列。
import Entity, PrimaryGeneratedColumn, Column from "typeorm";
@Entity()
export class User
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column(select: false)
password: string;
然后在您需要密码的验证/案例中
const users = await connection.getRepository(User)
.createQueryBuilder()
.select("user.id", "id")
.addSelect("user.password")
.getMany();
【讨论】:
以上是关于序列化:如何排除 json 响应中的实体列,但不排除 Nestjs 中的内部查询的主要内容,如果未能解决你的问题,请参考以下文章
如何从控制器 JSON 返回的实体字段中排除。 NestJS + Typeorm
如何将谷歌云自然语言实体情感响应转换为 Python 中的 JSON/dict?
如何使用 JsonConverter 在 System.Text.Json.JsonSerializer.Serialize() 中排除属性被序列化