I am new to the NestJs and i am stuck on problem with returning response entity from my backend.
The problem is that even when i return Promise-PostDTO-. It's still returns Post entity from database. With all the properties and nestjs ignore return type.
Do you know where can be problem? I though that automatic conversion works in both ways. Maybe problem is in returning Promise and not PostDTO.
I hope that someone can help me. Thanks
The code below.
post.entity.ts
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
} from 'typeorm';
@Entity()
export default class Post {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
title: string;
@Column()
perex: string;
@Column()
content: string;
@CreateDateColumn()
createdAt: Date;
}
post.dto.ts
import { IsString } from 'class-validator';
import { Exclude, Expose } from 'class-transformer';
@Exclude()
export class PostDTO {
@Expose()
@IsString()
readonly title: string;
@Expose()
@IsString()
readonly perex: string;
@Expose()
@IsString()
readonly content: string;
}
post.repository.ts
import { Repository, EntityRepository } from 'typeorm';
import Post from './post.entity';
@EntityRepository(Post)
export class PostRepository extends Repository<Post> {}
post.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import Post from './post.entity';
import { PostRepository } from './post.repository';
import { PostDTO, PostRO } from './post.dto';
@Injectable()
export class PostService {
constructor(
@InjectRepository(Post) private readonly postRepository: PostRepository,
) {}
async createPost(post: PostDTO): Promise<PostDTO> {
return await this.postRepository.save(post);
}
}
post.controller.ts
import {
Controller,
Get,
Post,
Body,
UseInterceptors,
ClassSerializerInterceptor,
} from '@nestjs/common';
import { PostService } from './post.service';
import { PostDTO } from './post.dto';
@Controller('post')
@UseInterceptors(ClassSerializerInterceptor)
export class PostController {
constructor(private readonly postService: PostService) {}
@Post()
async createPost(@Body() post: PostDTO): Promise<PostDTO> {
return await this.postService.createPost(post);
}
}
Based on the Jay McDoniel's answer i refactor my code to this.
I used custom nestjs interceptor that converts classes.
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { plainToClass } from 'class-transformer';
interface ClassType<T> {
new (): T;
}
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<Partial<T>, T> {
constructor(private readonly classType: ClassType<T>) {}
intercept(
context: ExecutionContext,
call$: CallHandler<Partial<T>>,
): Observable<T> {
return call$.handle().pipe(map(data => plainToClass(this.classType, data)));
}
}
I also refactor my DTO with class-transformer package.
import { IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { Exclude, Expose } from 'class-transformer';
@Exclude()
export class ArticleDTO {
@Expose()
@ApiProperty({ required: true })
@IsString()
readonly title: string;
@Expose()
@ApiProperty({ required: true })
@IsString()
readonly perex: string;
@Expose()
@ApiProperty({ required: true })
@IsString()
readonly content: string;
}
Usage of the new iterceptor in my controller.
import { Controller, Get, Post, Body, UseInterceptors } from '@nestjs/common';
import { ArticleService } from './article.service';
import { ArticleDTO } from './dto/article.dto';
import { TransformInterceptor } from 'src/transform.interceptor';
@Controller('articles')
@UseInterceptors(new TransformInterceptor(ArticleDTO))
export class ArticleController {
constructor(private readonly articleService: ArticleService) {}
@Get()
async getAllPosts(): Promise<ArticleDTO[]> {
return await this.articleService.getAllPosts();
}
@Post()
async createPost(@Body() post: ArticleDTO): Promise<ArticleDTO> {
return await this.articleService.createPost(post);
}
}
After these code updates it works as expected, so it returns DTO instead of DB Entity.