1

I want to create upload with swagger,use DTO and save the binary in my MongoDB

My DTO is:

import { ApiProperty } from '@nestjs/swagger';
import { Expose } from 'class-transformer';
import { IsNotEmpty, IsOptional } from 'class-validator';


export class GatewayDto {  
    
  @ApiProperty({ default: 'foo' })
  @IsNotEmpty()
  @Expose()
  name: string;
  
  @ApiProperty({default: 'XXXX:YYYY'})
  @IsNotEmpty()
  @Expose()
  token: string;

  @ApiProperty({default: '123'})
  @IsNotEmpty()
  @Expose()
  channelId: string;
  
  @ApiProperty({ default: true })  
  @IsNotEmpty()
  @Expose()
  public: string;

  @Expose()  
  @IsNotEmpty()
  logo: any;

}

my controller is:


 @Post('/')
    @ApiConsumes('multipart/form-data')
    @ApiBody({
        schema: {
            type: 'object',
            properties: {
                name: {
                    type: 'string',
                    default: 'foo'
                },
                token: {
                    type: 'string',
                    default: '11:22'
                },
                channelId: {
                    type: 'string',
                    default: '1234'
                },
                public: {
                    type: 'string',
                    default: 'true'
                },
                logo: {
                    type: 'string',
                    format: 'binary',                                        
                },
            },
        },
    })
    @UseInterceptors(FileInterceptor('logo'))
    @HttpCode(HttpStatus.CREATED)
    @ApiCreatedResponse(GatewayConfigSwagger.API_CREATE_GATEWAY)
    //@Serialize(GatewayDto)
    public async create(
        @UploadedFile('file') file,
        @Body() data: GatewayDto,
        @Request() request
    ) {
        console.log(data);
        
        if (file) {
            data['logo'] = file.buffer;
        }
        //return this.gatewayService.create(request.user.userId._id, data);
    }

When I create my request, I get this error:

"logo should not be empty"

My curl is:

curl -X 'POST' \
  'http://localhost:3001/api/v1/gateways' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer xxx \
  -H 'Content-Type: multipart/form-data' \
  -F 'name=foo' \
  -F 'token=11:22' \
  -F 'channelId=1234' \
  -F 'public=true' \
  -F 'logo=@image.png;type=image/png'

If I remove the logo field from DTO I'm able to store my image.

I tried to create a interceptor according to this answer File uploading along with other data in Swagger NestJs


import { BadGatewayException, CallHandler, ExecutionContext, Injectable, NestInterceptor, UnauthorizedException } from "@nestjs/common";
import { catchError, map, Observable, throwError } from "rxjs";

export interface Response<T> {
    statusCode: number;
    data: T;    
}

@Injectable()
export class FileExtender implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
      const req = context.switchToHttp().getRequest();
      console.log(req.body)
      
      return next.handle();
    }
  }

and my req.body doesn't have logo field

UPDATE

I updated my interceptor with

import { BadGatewayException, CallHandler, ExecutionContext, Injectable, NestInterceptor, UnauthorizedException } from "@nestjs/common";
import { catchError, map, Observable, throwError } from "rxjs";

export interface Response<T> {
    statusCode: number;
    data: T;    
}

@Injectable()
export class FileExtender implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
      const req = context.switchToHttp().getRequest();
      
      req.body['logo'] = req.file.buffer;   
      console.log(req.body)
      
      return next.handle();
    }
  }

Now it works, but is it the best practice?

monkeyUser
  • 4,301
  • 7
  • 46
  • 95

1 Answers1

0

Try using the @IsOptional validator on the logo property in the DTO file. It is used to mark nullable fields. Validation will pass if it is null or undefined and will be enforced as per other validators otherwise. Application logic must handle this accordingly.

You can take a look at all available validators here. You can combine any number of them on any DTO class property.

fmi21
  • 485
  • 3
  • 15