嵌套js POST请求无法识别DTO方法

问题描述 投票:0回答:2

我遇到一个触发POST端点的麻烦,该端点触发了我的postgres DB的typeorm repository.save()方法。

这是我的DTO对象:

import { ApiProperty } from '@nestjs/swagger/';
import { IsString, IsUUID} from 'class-validator';

import { Client } from '../../../models';
import { User } from '../../../user.decorator';


export class ClientDTO implements Readonly<ClientDTO> {
    @ApiProperty({ required: true })
    @IsUUID()
    id: string;


    @ApiProperty({ required: true })
    @IsString()
    name: string;

    public static from(dto: Partial<ClientDTO>) {
      const cl = new ClientDTO();
      cl.id = dto.id;
      cl.name = dto.name;
      return cl;
    }

    public static fromEntity(entity: Client) {
      return this.from({
        id: entity.id,
        name: entity.name,
      });
    }

    public toEntity = (user: User | null) => {
      const cl = new Client();
      cl.id = this.id;
      cl.name = this.name;
      cl.createDateTime = new Date();
      cl.createdBy = user ? user.id : null;
      cl.lastChangedBy = user ? user.id : null;
      return cl;
    }
  }

我在POST上的控制器-/client

import { 
    Body,
    Controller, 
    Get, Post 
} from '@nestjs/common';

import { ClientDTO } from './dto/client.dto';
import { ClientService } from './client.service';
import { User } from 'src/user.decorator';

@Controller('client')
export class ClientController {
    constructor(
        private clientService: ClientService
    ) { }

    @Get()
    public async getAllClients(): Promise<ClientDTO[]> {
        return this.clientService.getAllClients();
    }

    @Post()
    public async createClient(@User() user: User, @Body() dto: ClientDTO): Promise<ClientDTO> {
        return this.clientService.createClient(dto, user);
    }
}

以及我的服务:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { Client } from '../../models';
import { ClientDTO } from './dto/client.dto';
import { User } from '../../user.decorator';


@Injectable()
export class ClientService {
    constructor(
        @InjectRepository(Client) private readonly clientRepository: Repository<Client>
    ) {}

    public async getAllClients(): Promise<ClientDTO[]> {
        return await this.clientRepository.find()
            .then(clients => clients.map(e => ClientDTO.fromEntity(e)));
    }

    public async createClient(dto: ClientDTO, user: User): Promise<ClientDTO> {
        return this.clientRepository.save(dto.toEntity(user))
            .then(e => ClientDTO.fromEntity(e));
    }
}

我收到500条内部服务器错误,并显示日志消息,指出我的ClientDTO.toEntity不是函数。

TypeError: dto.toEntity is not a function
    at ClientService.createClient (C:\...\nest-backend\dist\features\client\client.service.js:29:47)
    at ClientController.createClient (C:\...\nest-backend\dist\features\client\client.controller.js:27:35)
    at C:\...\nest-backend\node_modules\@nestjs\core\router\router-execution-context.js:37:29
    at process._tickCallback (internal/process/next_tick.js:68:7)

我很困惑,因为这仅通过http请求发生。我有一个脚本,可以在一个名为seed.ts的Docker容器中重新启动它后,为我的开发数据库添加种子:

import * as _ from 'lodash';

import { Client } from '../models';
import { ClientDTO } from '../features/client/dto/client.dto';
import { ClientService } from '../features/client/client.service';
import { configService } from '../config/config.service';
import { createConnection, ConnectionOptions } from 'typeorm';
import { User } from '../user.decorator';

async function run() {

  const seedUser: User = { id: 'seed-user' };

  const seedId = Date.now()
    .toString()
    .split('')
    .reverse()
    .reduce((s, it, x) => (x > 3 ? s : (s += it)), '');

  const opt = {
    ...configService.getTypeOrmConfig(),
    debug: true
  };

  const connection = await createConnection(opt as ConnectionOptions);
  const clientService = new ClientService(connection.getRepository(Client));

  const work = _.range(1, 10).map(n => ClientDTO.from({
      name: `seed${seedId}-${n}`,
    }))
######################## my service calls ClientDTO.toEntity() without issue ###########################
    .map(dto => clientService.createClient(dto, seedUser) 
      .then(r => (console.log('done ->', r.name), r)))

  return await Promise.all(work);
}

run()
  .then(_ => console.log('...wait for script to exit'))
  .catch(error => console.error('seed error', error));

这使我认为我缺少简单/明显的内容。

谢谢!

javascript typescript http nest typeorm
2个回答
0
投票

您的dto通过api调用进入时不是基于类的对象-它只是一个通用对象。因此,它不能具有方法,因此您的toEntity方法将不起作用。您收到的错误消息是红色鲱鱼,并没有告诉您失败的真正原因。

您可以通过基于您的类创建一个新对象,然后在该新对象上调用一个方法来从纯对象dto复制属性,或者使用类转换器库,或者通过您想要的任何方法来解决此问题达到相同的结果。


0
投票

dto在控制器中像这样dto: ClientDTO这样声明的事实不足以创建类的实例。这只是您和项目中其他开发人员的指示,以防止在应用程序的其余部分中滥用dto对象。

为了拥有类的实例,并使用类中的方法,您必须像这样显式设置映射:

@Post()
public async createClient(@User() user: User, @Body() dto: ClientDTO): Promise<ClientDTO> {
    const client = ClientDTO.from(dto);
    return this.clientService.createClient(client, user);
}

假设ClientDTO.from是用于dto中包含的数据的正确函数。如果没有,请对其进行调整,然后创建一个新的或constructor

© www.soinside.com 2019 - 2024. All rights reserved.