NestJs: DTO showing all query parameters - javascript

I'm trying to use 2 separate dto for query parameters in NestJs. However, on printing both dtos are showing same properties. Is there any way to separate them.
// dto code
export class PageDto {
#Type(() => Number)
#IsInt()
page: number;
#Type(() => Number)
#IsInt()
limit: number;
}
export class MyDto {
#ApiPropertyOptional()
#IsString()
#IsOptional()
status: string;
#ApiPropertyOptional()
#IsString()
#IsOptional()
source: string;
}
Api request:
GET url?page=1&limit=10&status='active'&source='firebase'
controller:
#Get()
async get(
#Query() myDto: MyDto,
#Query() pageDto: PageDto,
) {
console.log({pageDto}, {myDto});
}
Console statement prints:
{
pageDto: {
page: 1,
limit: 10,
status: 'active',
source: 'firebase'
}
}
{
myDto: {
page: 1,
limit: 10,
status: 'active',
source: 'firebase'
}
}
Required:
{
pageDto: {
page: 1,
limit: 10
}
}
{
myDto: {
status: 'active',
source: 'firebase'
}
}
Ideally, pageDto and myDto should show their respective properties.

You'll need to set whitelist: true in your ValidationPipe options to tell class-transformer and class-validator to strip out the properties that don't exist on the DTO.
Reference to the docs

Related

Wrong property is included in created object

I am currently developing application using nestjs with fastify adapter
But something weird on object construction.
Following all the related classes, and methods:
Controller endpoint handler
#Get()
#ApiOperation({
description: "Get all user admin",
})
async findAll(
#Query() filter: GetListAdminReqFilter,
#Query() pagination: PaginatedReqDto
): Promise<RestRespDto<GetListAdminRespDto[]>> {
return new RestRespDto({
data: await this.adminService.findAll(
new GetListAdminReqDto(filter, pagination)
),
});
}
The request dto
export class GetListAdminReqDto extends PaginatedReqDto {
constructor(filter: GetListAdminReqFilter, pagination: PaginatedReqDto) {
super();
this.filter = filter;
this.pagination = pagination.pagination;
this.page = pagination.page;
}
filter?: GetListAdminReqFilter;
}
The pagination req dto
export class PaginatedReqDto {
#ApiPropertyOptional({
default: 10,
description: "Number of items to retrieve",
})
pagination?: number;
#ApiPropertyOptional({
description: "Page number, e.g:1 ",
default: 1,
})
page?: number;
}
The filter
export class GetListAdminReqFilter {
#ApiPropertyOptional()
#IsOptional()
name?: string;
#ApiPropertyOptional()
#IsOptional()
email?: string;
#ApiPropertyOptional()
#IsOptional()
divisi?: string;
#ApiPropertyOptional({ enum: AdminStatusEnum})
#IsOptional()
status?: AdminStatusEnum;
}
The result of GetListAdminReqDto object is following:
{
filter: [Object: null prototype] {
pagination: '10',
page: '1',
name: 'asdfasdf',
email: 'asdfasdf',
divisi: 'asdfasdf'
},
pagination: '10',
page: '1'
}
Why pagination and page is property also included in filter?, i dont understand what happened, any help will be appreciated
My guess is that the #Query() filter: GetListAdminReqFilter is receiving the page and pagination properties because your ValidationPipe is allowing properties outside of the DTO. You could alter the global ValidationPipe.whitelist property:
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // this prevents properties outside the DTO to be ignored
}),
);

how to exclude required entities from a response in TypeORM with NestJS

I have an entity
#Column()
name: string;
#IsEmail()
email: string;
#Column({ select: false })
autogeneratedCode: string;
I'm getting name and string only in my GET request response which is expected.
But when I'm hit my POST Api with body, it is returning name, email, autogeneratedCode as well.
I need to hide autogeneratedCode in all CRUD responses.
Is there anyway to do that? or Am I missing something here?
You can use #Exclude() from 'class-transformer'
Example
import { Exclude } from 'class-transformer';
#Entity()
export class User {
#Column()
name: string;
#IsEmail()
email: string;
#Column({ select: false })
#Exclude()
autogeneratedCode: string;
constructor(entity: Partial<User>) {
Object.assign(this, entity);
}
}
Then you can use the constructor to create a new object excluding the #Exclude() properties.
export class UserService {
constructor(
#InjectRepository(User)
private userRepository: Repository<User>
) {}
public async createUser(user: User): Promise<User> {
return new User(
await this.userRepository.save(user)
);
}
}
NestJS Doc on Serialization
https://docs.nestjs.com/techniques/serialization#exclude-properties

Nestjs ClassSerializerInterceptor doesn't display _id

I have an issue properly exposing the _id using the Serializer.
I use:
#UseInterceptors(ClassSerializerInterceptor)
#SerializeOptions({ strategy: 'excludeAll' })
The defined Class:
export class UpdatedCounts {
#Expose()
_id: ObjectId;
#Expose()
aCount: number;
#Expose()
bCount: number;
constructor(partial: Partial<MyDocument>) {
Object.assign(this, partial);
}
}
The object in console.log() before it runs through the Serializer
{
_id: new ObjectId("61c2256ee0385774cc85a963"),
bannerImage: 'placeholder2',
previewImage: 'placeholder',
aCount: 1,
bCount: 0,
}
The object being returned:
{
"_id": {},
"aCount": 1,
"bCount": 0
}
So what happened to my _id?
I tried using string type instead of ObjectId but that also does not work
I do not want to use #Exclude since there are 10 more props which I left out in the example console.log(), and it should be easier to exclude all and just use these 3
Just use #Transform:
#Expose()
#Transform((params) => params.obj._id.toString())
_id: ObjectId;
You can not just send ObjectId with JSON. You must convert it to a string.

How to write nested DTOs in NestJS

I am a beginner in NestJS and I want to write a DTO for below structure -
{
something: {
info: {
title: string,
score: number,
description: string,
time: string,
DateOfCreation: string
},
Store: {
item: {
question: string,
options: {
item: {
answer: string,
description: string,
id: string,
key: string,
option: string
}
}
}
}
}
}
I want to write a DTO for that nested Data object. I can't find a solid example for writing nested DTO in NestJS. I am a beginner in NestJS and I have never worked with DTO before. So please don't assume that I know something. I am using it with Mongoose.
You will have to create separate classes for each object in your schema and a main class which will import all the classes.
class Info {
readonly title:string
readonly score:number
readonly description:string
readonly dateOfCreation:Date
}
export class SampleDto {
#Type(() => Info)
#ValidateNested()
readonly info: Info
...Follow same for the rest of the schema
}
Refer: https://github.com/typestack/class-validator#validating-nested-objects
//example :
export class UserBaseDto {
#ApiProperty({
type: String,
required: true,
description: 'email user, minlength(4), maxlength(40)',
default: "test#email.com",
})
#IsString()
#MinLength(4)
#MaxLength(40)
#IsNotEmpty()
email: string;
//....enter code here
}

How to Make Relation in LoopBack v4 With Include Key

https://loopback.io/doc/en/lb4/HasMany-relation.html
I followed this steps and then tried to get data with include but I get 500.
500 Error: Invalid "filter.include" entries: {"relation":"ranks"}
What I want is to get games object with its related ranks.
Rank Model
import { Entity, model, property, belongsTo } from '#loopback/repository';
import { Game, GameWithRelations } from './game.model';
#model({ settings: { strict: 'filter' } })
export class Rank extends Entity {
#property({
type: 'string',
id: true,
})
id?: string;
#property({
type: 'string',
})
name?: string;
#property({
type: 'string',
})
shortName?: string;
#property({
type: 'string',
})
avatar?: string;
#belongsTo(() => Game)
gameId: string;
constructor(data?: Partial<Rank>) {
super(data);
}
}
export interface RankRelations {
game?: GameWithRelations;
}
export type RankWithRelations = Rank & RankRelations;
Game Model
import { Entity, model, property, embedsMany, hasMany } from '#loopback/repository';
import { Rank, RankWithRelations } from './rank.model';
import { HasMany } from 'loopback-datasource-juggler';
#model({ settings: { strict: 'filter' } })
export class Game extends Entity {
#property({
type: 'string',
id: true,
})
id?: string;
#property({
type: 'string',
required: true,
})
name?: string;
#property({
type: 'string',
})
shortName?: string;
#property({
type: 'string',
})
avatar?: string;
#hasMany<Rank>(() => Rank, { keyTo: 'gameId' })
ranks?: Rank[];
constructor(data?: Partial<Game>) {
super(data);
}
}
export interface GameRelations {
}
export type GameWithRelations = Game & GameRelations;
Game Controller
// in this method
// 500 Error: Invalid "filter.include" entries: {"relation":"ranks"}
#get('/games/{id}')
async findById(#param.path.string('id') id: string): Promise<Game> {
return await this.gameRepository.findById(id, { include: [{ relation: 'ranks' }] });
}
Please run your application with DEBUG=loopback:repository:relation-helpers, that way you will get a debug message explaining why filter.include entry was rejected.
You can find the code building the error message here:
https://github.com/strongloop/loopback-next/blob/97ba7893e253bfc2967ac08e408b211c9b9b7f40/packages/repository/src/relations/relation.helpers.ts#L96-L100
The most likely cause: your GameRepository does not have any InclusionResolver registered for ranks relation.
Please refer to our todo-list example to see how to register inclusion resolver. Cross-posting from https://github.com/strongloop/loopback-next/blob/97ba7893e253bfc2967ac08e408b211c9b9b7f40/examples/todo-list/src/repositories/todo-list.repository.ts#L41-L46:
this.todos = this.createHasManyRepositoryFactoryFor(
'todos',
todoRepositoryGetter,
);
this.registerInclusionResolver('todos', this.todos.inclusionResolver);

Categories