Сериализация ответа Nestjs с массивом объектов - PullRequest
0 голосов
/ 12 февраля 2019

Я хочу сериализовать ответ контроллера с помощью метода сериализации nestjs.Я не нашел никакого подхода, и мое решение выглядит следующим образом:

Сущность пользователя

export type UserRoleType = "admin" | "editor" | "ghost";

@Entity()
export class User {
    @PrimaryGeneratedColumn() id: number;

    @Column('text')
        username: string;
    @Column('text') 
        password: string;
    @Column({
        type: "enum",
        enum: ["admin", "editor", "ghost"],
        default: "ghost"
    })
    roles: UserRoleType;
        @Column({ nullable: true })
                profileId: number;  
}

Классы ответа пользователя

import { Exclude } from 'class-transformer';

export class UserResponse {
    id: number;

    username: string;

    @Exclude()
    roles: string;

    @Exclude()
    password: string;

    @Exclude()
    profileId: number;  

    constructor(partial: Partial<UserResponse>) {
        Object.assign(this, partial);
    }
}

import { Exclude, Type } from 'class-transformer';
import { User } from 'src/_entities/user.entity';
import { UserResponse } from './user.response';

export class UsersResponse {

    @Type(() => UserResponse)
    users: User[]   

    constructor() { }
}

Контроллер

@Controller('user')
export class UsersController {
    constructor(
        private readonly userService: UserService
    ) {

    }
    @UseInterceptors(ClassSerializerInterceptor)
    @Get('all')
    async findAll(
    ): Promise<UsersResponse> {
        let users = await this.userService.findAll().catch(e => { throw new   NotAcceptableException(e) })
        let rsp =new UsersResponse() 
        rsp.users = users
        return rsp
    }

Это работает, но я должен явно назначить результат запроса базы данных члену пользователя ответа.Есть ли способ лучше?Большое спасибо

Здесь фактический Ответ и требуемый результат, для лучшего объяснения.

Результат в этом Подходе

{
  "users": [
    {
      "id": 1,
      "username": "a"
    },
    {
      "id": 2,
      "username": "bbbbbb"
    }
  ]
}

Результат Требуется

{
    {
      "id": 1,
      "username": "a"
    },
    {
      "id": 2,
      "username": "bbbbbb"
    }
}

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Ого, как легко, если я знаю!Отлично, это решает мою проблему.Также ваша рекомендация для User Entity с декоратором класса-преобразователя @Exclue ().

И я знаю, что мне не нужен пользовательский класс UsersResponse в этом случае использования.Это решение было тем, что я искал, но я перебил этот довольно простой способ

Большое спасибо за ваш сверхбыстрый ответ и решение проблемы.

Привет Берлину из Ростока:)

Вот мой последний подход:

Контроллер

@UseInterceptors(ClassSerializerInterceptor)
@Get('all')
async findAll(
): Promise<User> {
    return await this.userService.findAll().catch(e => { throw new NotAcceptableException(e) })
}

Права пользователя

import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn, OneToMany } from 'typeorm';
import { Profile } from './profile.entity';
import { Photo } from './photo.entity';
import { Album } from './album.entity';
import { Exclude } from 'class-transformer';

export type UserRoleType = "admin" | "editor" | "ghost";

@Entity()
export class User {
    @PrimaryGeneratedColumn() id: number;
    @Column('text')
    username: string;

    @Exclude()
    @Column('text')
    password: string;

    @Column({
        type: "enum",
        enum: ["admin", "editor", "ghost"],
        default: "ghost"
    })
    roles: UserRoleType;

    @Exclude()
    @Column({ nullable: true })
    profileId: number;

    @OneToMany(type => Photo, photo => photo.user)
    photos: Photo[];

    @OneToMany(type => Album, albums => albums.user)
    albums: Album[];

    @OneToOne(type => Profile, profile => profile.user)
    @JoinColumn()
    profile: Profile;
}

Результат ответа

[
  {
    "id": 1,
    "username": "a",
    "roles": "admin"
  },
  {
    "id": 2,
    "username": "bbbbbb",
    "roles": "ghost"
  }
]
0 голосов
/ 12 февраля 2019

Я бы порекомендовал поместить в свой класс сущности User декораторы @Exclude, а не дублировать свойства в UserResponse.Следующий ответ предполагает, что вы это сделали.


Плоский ответ

Если вы посмотрите на код ClassSerializerInterceptor, вы можете увидеть, чтоон автоматически обрабатывает массивы:

return isArray
  ? (response as PlainLiteralObject[]).map(item =>
      this.transformToPlain(item, options),
    )
  : this.transformToPlain(response, options);

Однако он преобразует их только при непосредственном возвращении массива, поэтому return users вместо return {users: users}:

@UseInterceptors(ClassSerializerInterceptor)
@Get('all')
async findAll(): Promise<User> {
    return this.userService.findAll()
}

Вложенный ответ

Если вам нужен вложенный ответ, то ваш путь - хорошее решение.Кроме того, вы можете вызвать serialize преобразователя класса напрямую, вместо использования ClassSerializerInterceptor.Он также обрабатывает массивы автоматически:

import { serialize } from 'class-transformer';

@Get('all')
async findAll(): Promise<UsersResponse> {
  const users: User[] = await this.userService.findAll();
  return {users: serialize(users)};
}
...