nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
67.84k stars 7.65k forks source link

FileInterceptor and FilesInterceptor for fastify #7018

Closed chanphiromsok closed 3 years ago

chanphiromsok commented 3 years ago

install-package yarn add fastify-multer main.ts

import { configSwagger } from './config/swagger/config-swagger';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import 'reflect-metadata';
import { SwaggerModule } from '@nestjs/swagger';
import { bold } from 'chalk';
import path from 'path';
import { option } from './config/security/helmet';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { contentParser } from 'fastify-multer';

async function bootstrap(): Promise<void> {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );
  app.register(contentParser);
  app.useStaticAssets({ root: path.join(__dirname, '../../backend/') });
  app.enableCors(option);
  SwaggerModule.setup('clothe-api', app, configSwagger(app));
  await app.listen(3000, '0.0.0.0');
  console.log(bold.blue('RUNNING ON PORTS', await app.getUrl()));
}
bootstrap();

fastify-file-interceptor.ts

import {
  CallHandler,
  ExecutionContext,
  Inject,
  mixin,
  NestInterceptor,
  Optional,
  Type,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import FastifyMulter from 'fastify-multer';
import { Options, Multer } from 'multer';

type MulterInstance = any;
export function FastifyFileInterceptor(
  fieldName: string,
  localOptions: Options
): Type<NestInterceptor> {
  class MixinInterceptor implements NestInterceptor {
    protected multer: MulterInstance;

    constructor(
      @Optional()
      @Inject('MULTER_MODULE_OPTIONS')
      options: Multer
    ) {
      this.multer = (FastifyMulter as any)({ ...options, ...localOptions });
    }

    async intercept(
      context: ExecutionContext,
      next: CallHandler
    ): Promise<Observable<any>> {
      const ctx = context.switchToHttp();

      await new Promise<void>((resolve, reject) =>
        this.multer.single(fieldName)(
          ctx.getRequest(),
          ctx.getResponse(),
          (error: any) => {
            if (error) {
              // const error = transformException(err);
              return reject(error);
            }
            resolve();
          }
        )
      );

      return next.handle();
    }
  }
  const Interceptor = mixin(MixinInterceptor);
  return Interceptor as Type<NestInterceptor>;
}

fastify-files-interceptor.ts

import {
  CallHandler,
  ExecutionContext,
  Inject,
  mixin,
  NestInterceptor,
  Optional,
  Type,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import FastifyMulter from 'fastify-multer';
import { Options, Multer } from 'multer';

type MulterInstance = any;
export function FastifyFilesInterceptor(
  fieldName: string,
  maxCount?: number,
  localOptions?: Options
): Type<NestInterceptor> {
  class MixinInterceptor implements NestInterceptor {
    protected multer: MulterInstance;

    constructor(
      @Optional()
      @Inject('MULTER_MODULE_OPTIONS')
      options: Multer
    ) {
      this.multer = (FastifyMulter as any)({ ...options, ...localOptions });
    }

    async intercept(
      context: ExecutionContext,
      next: CallHandler
    ): Promise<Observable<any>> {
      const ctx = context.switchToHttp();

      await new Promise<void>((resolve, reject) =>
        this.multer.array(fieldName, maxCount)(
          ctx.getRequest(),
          ctx.getResponse(),
          (error: any) => {
            if (error) {
              // const error = transformException(err);
              return reject(error);
            }
            resolve();
          }
        )
      );

      return next.handle();
    }
  }
  const Interceptor = mixin(MixinInterceptor);
  return Interceptor as Type<NestInterceptor>;
}

All code above I just copy and implement package from fastify-multer its base on multer express

Example SIngle file

@ApiConsumes('multipart/form-data')
  @UseInterceptors(
    FastifyFileInterceptor('product_image', {
      storage: diskStorage({
        destination: './upload/product',
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
    })
  )
  @Post('create')
  uploadFile(
    @Req() req: Request,
    @UploadedFile() file: Express.Multer.File,
    @Body() productDto: CreateProductDto
  ) {
    return file
  }

Example Multiple files

@ApiConsumes('multipart/form-data')
  @Post('multiple')
  @UseInterceptors(
    FastifyFilesInterceptor('product_image', 20, {
      storage: diskStorage({
        destination: './upload/product',
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
    })
  )
  uploadMultipleFiles(
    @Req() req: Request,
    @UploadedFiles() files: Express.Multer.File[]
  ) {
// handle your file here
    return files
  }

To sum up I just copy code from source code and implement it I hope @Admin would implement it in package "@nestjs-platform-fastify" one more thing page "fastify-file-interceptor.ts and fastify-files-interceptor.ts * is missing function transformException

**Note the interface Express.Multer.File I define for @UploadFile() and @UploadFiles() is from Express because fastify-multer is base on multer express

kamilmysliwiec commented 3 years ago

Please search through some of our old issues on this (this has been discussed several times in the past).