简体   繁体   中英

NestJS Fastify - Best way to upload file on S3

So, I have a few issues. main.ts

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
    { bufferLogs: true, bodyParser: false },
  );

  const configService = app.get(ConfigService);
  const PORT = configService.get('port');

  app.register(fmp, { attachFieldsToBody: true });

  await app.listen(PORT);

  logger.log(`Application is running on: ${await app.getUrl()}`);
}

author.controller.ts

@Post('/create')
  async createAuthor(
    @AuthUser() user: any,
    @Body() createAuthorDto: CreateAuthorDto,
  ): Promise<BaseResponseEntity> {
    return await this.authorsService.createAuthor(
      user,
      createAuthorDto,
    );
  }

I had to add { attachFieldsToBody: true } or else the createAuthorDto becomes undefined , but after adding that, the createAuthorDto becomes something like this:

<ref *1> {
  first_name: {
    fieldname: 'first_name',
    mimetype: undefined,
    encoding: '7bit',
    value: 'Deep',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  last_name: {
    fieldname: 'last_name',
    mimetype: undefined,
    encoding: '7bit',
    value: 'Mandal',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  email_id: {
    fieldname: 'email_id',
    mimetype: undefined,
    encoding: '7bit',
    value: 'author6@gmail.com',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  passwd: {
    fieldname: 'passwd',
    mimetype: undefined,
    encoding: '7bit',
    value: '123',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  delete_allowed: {
    fieldname: 'delete_allowed',
    mimetype: undefined,
    encoding: '7bit',
    value: 'true',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  posted_by_admin: {
    fieldname: 'posted_by_admin',
    mimetype: undefined,
    encoding: '7bit',
    value: 'true',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  status: {
    fieldname: 'status',
    mimetype: undefined,
    encoding: '7bit',
    value: '1',
    fieldnameTruncated: false,
    valueTruncated: false,
    fields: [Circular *1]
  },
  profile_image: {
    fieldname: 'profile_image',
    filename: 'fields.png',
    encoding: '7bit',
    mimetype: 'image/png',
    file: FileStream {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      bytesRead: 17081,
      truncated: false,
      _read: [Function (anonymous)],
      [Symbol(kCapture)]: false
    },
    fields: [Circular *1],
    _buf: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 02 e5 00 00 00 a8 08 02 00 00 00 c8 01 07 32 00 00 00 03 73 42 49 54 08 08 08 db e1 4f e0 00 00 ... 17031 more bytes>,
    toBuffer: [AsyncFunction: toBuffer]
  },
  logo: {
    fieldname: 'logo',
    filename: 'london.png',
    encoding: '7bit',
    mimetype: 'image/png',
    file: FileStream {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      bytesRead: 160296,
      truncated: false,
      _read: [Function (anonymous)],
      [Symbol(kCapture)]: false
    },
    fields: [Circular *1],
    _buf: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 05 56 00 00 03 00 08 02 00 00 00 40 5c ab 95 00 00 00 03 73 42 49 54 08 08 08 db e1 4f e0 00 00 ... 160246 more bytes>,
    toBuffer: [AsyncFunction: toBuffer]
  }
}

While my actual createAuthorDto is something like this:

export class CreateAuthorDto {
  @IsString()
  first_name: string;

  @IsString()
  last_name: string;

  @IsString()
  email_id: string;

  @IsString()
  passwd: string;

  passdis?: string;

  @IsBoolean()
  delete_allowed: boolean;

  @IsBoolean()
  posted_by_admin: boolean;

  @IsNumber()
  status: number;
}

I can work with what I'm getting but I feel like there is a better way to handle multipart/form data when using nestjs fastify.

You can actually follow the file upload guide on the official nestjs doc .

I think the problem in your code is that the output of createAuthorDto has too many redundant properties.

as you can see on the link that I shared, you can intercept the request with @UseInterceptors() which extracts a file and pass it with Express.Multer.File. Of course the other data will simply pass through your custom dto class.

@Post('create')
@UseInterceptors(FileInterceptor('file'))
uploadFile(
  @UploadedFile() file: Express.Multer.File,
  @Body() createAuthorDto: CreateAuthorDto
) {
  console.log(file);
  console.log(createAuthorDto);
}

but in your case, you need to receive two files(profile_image, logo). You can also handle multiple images with specific field names like this.

@Post('create')
@UseInterceptors(FileFieldsInterceptor([
  { name: 'profile_image', maxCount: 1 },
  { name: 'logo', maxCount: 1 },
]))
uploadFile(
  @UploadedFiles() files: { profile_image?: Express.Multer.File[], logo?: Express.Multer.File[] }, 
  @Body() createAuthorDto: CreateAuthorDto,
) {
  console.log(files);
  console.log(createAuthorDto);
}

Now you can handle two different types of data separately, File and Dto without the redundant properties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM