18

I feel like a combination of this thread and this thread is what I need to implement, I'm having trouble drawing them together.

I have a DTO that contains an enum.

Using Postman, I am sending a PurchasableType of FOO and expecting to get an error of some sort. Reading through the above links, it seems like the process is quite involved; which makes me thing I'm completely missing the point.

How can I use the validation pipe(s) to make sure only the values in the purchasable-type.enum.ts are allowed?

Thank you for any suggestions!

// create-order.dto.ts

import { IsEmail, IsNotEmpty, IsEnum } from 'class-validator';
import { PurchasableType } from '../enum/purchaseable-type.enum';

export class CreateOrderDto {
  @IsNotEmpty()
  readonly userId: string;

  @IsNotEmpty()
  readonly locationId: string;

  @IsNotEmpty()
  @IsEnum(PurchasableType)
  readonly purchasableType: PurchasableType;

  @IsNotEmpty()
  @IsEmail()
  readonly email: string;
}
// purchasable-type.enum.ts

export enum PurchasableType {
  CLINIC = 'CLINIC',
  EVENT = 'EVENT',
  LESSON = 'LESSON',
  RESERVATION = 'RESERVATION',
  TEAM = 'TEAM',
}

EDIT

It seems I was also not defining the entity correctly, and that may have been the main issue. I am still curious if my implementation good/bad.

// order.entity.ts

...
import { PurchasableType } from '../enum/purchaseable-type.enum';

@Entity()
export class Order extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

@Column({
    type: 'enum',
    enum: PurchasableType,
  })

Now when I send a purchasableType of foo I am getting a 500 error. If I send any valid value that is within the enum I am getting a 200/201.

EDIT 2

Sure - here is a bit wider view of what I've got. Everything seems to be working properly, I'd just like to have a better grasp of what was really happening.

// event.controller.ts

@Post('/:id/orders')
  async purchaseEventTickets(@Body() createOrderDto: CreateOrderDto): 
    Promise<Order> {
    return await this.eventService.purchaseEventTickets(createOrderDto);
  }

// create-order.dto.ts

export class CreateOrderDto {
    @IsNotEmpty()
    @IsEnum(PurchasableType)
    readonly purchasableType: PurchasableType;
}
// event.service.ts

async purchaseEventTickets(createOrderDto: CreateOrderDto): Promise<Order> {
    ...
    return await this.orderRepository.createOrder(createOrderDto);
}

// order.repository.ts

async createOrder(createOrderDto: CreateOrderDto): Promise<Order> {
    const { purchasableType } = createOrderDto;

    const order = this.create();

    order.purchasableType = purchasableType;

    try {
        await order.save();
    } catch (error) {
        this.logger.error(`Failed to create the order: ${error.stack}`);

        throw new InternalServerErrorException();
    }

    return order;
}

Using Postman, if I send an invalid value of "Foo" as a PurchasableType I get the expected error.

2
  • could you provide us a bit more info about the way you use the validation pipe ? To me the 500 error seems to be thrown by the ORM, not the validation pipe, which is not what you expect I guess Commented Aug 17, 2020 at 17:43
  • Sure! I've updated my question. I hope i've provided a bit more information. Thank you for your time to help! Commented Aug 19, 2020 at 21:44

6 Answers 6

33

It took me a while to find a good solution.

@ApiProperty({
  description: 'List of enums',
  isArray: true,
  enum: MyEnum
})
@IsEnum(MyEnum, { each: true })
prop: MyEnum[];
Sign up to request clarification or add additional context in comments.

2 Comments

Where is @ApiProperty impoerted from?
@KaranKumar good questions, that is a swagger(openapi) decorator I use for creating swagger documentation. For this questions is not relevant but it could be useful for those using openapi.
6

Here is what your create-dto looks like that contains an enum.

// create-order.dto.ts

import { IsEmail, IsNotEmpty, IsEnum } from 'class-validator';
import { PurchasableType } from '../enum/purchaseable-type.enum';

export class CreateOrderDto {

    ...

    @IsNotEmpty()
    @IsEnum(PurchasableType)
    readonly purchasableType: PurchasableType;
}

Here is what that enum file looks like:

// purchasable-type.enum.ts

export enum PurchasableType {
  CLINIC = 'CLINIC',
  EVENT = 'EVENT',
  LESSON = 'LESSON',
  RESERVATION = 'RESERVATION',
  TEAM = 'TEAM',
}

From there I can confidently expect the value of the enum to be one of the above values. If some other value comes through, nest will throw a validation error.

Additionally, If you are attempting to use a nested object (or something with multiple attributes or an array) you can do something like this in your DTO:

import { PurchasableType } from '../interface/purchasable-type.interface';
...

@ApiProperty()
@IsArray()
@ArrayMinSize(7)
@ArrayMaxSize(7)
@ValidateNested({ each: true })
@Type(() => PurchasableType)
@IsNotEmpty()
readonly PurchasableType: PurchasableType[];

...

Comments

5
  @IsArray()
  @IsEnum(enum, { each: true })
  prop: enum[]

Comments

2
  @IsEnum(myEnum, { each: true })
  @Transform((value) => myEnum[value])
  tags: myEnum[];

Comments

1
enum PARAM_TYPE {
  VENUE_NAME = 'VENUE_NAME',
  USER_NAME = 'USER_NAME',
}

@ApiPropertyOptional({
isArray: true,
 enum: ENUM_TYPE
})
@IsEnum(PARAM_TYPE, { each: true })
params: PARAM_TYPE[];

1 Comment

Thank you for your interest in contributing to the Stack Overflow community. This question already has a few answers—including one that has been extensively validated by the community. Are you certain your approach hasn’t been given previously? If so, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient. Can you kindly edit your answer to offer an explanation?
0

None of the above worked for me, I did it this way:

@Column({ type: 'enum', enum: MyEnum, array: true })
myProperty: MyEnum[];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.