skip to Main Content

I initialize MutlerModule to app.module:

MulterModule.registerAsync({
    imports: [ ConfigModule ],
    inject: [ ConfigService ],

    async useFactory(configService: ConfigService)
    {
        const uploadFolder = configService.get<IConfig[ "uploadFolder" ]>("uploadFolder");

        return {
            storage: diskStorage({
                destination: uploadFolder,
                filename(req, file, cb)
                {
                    const filename = `${ Date.now() }-${ file.originalname }`;

                    cb(null, filename);
                }
            })
        };
    }
}),

In uploadFolder we have uploads. Further for some route I want to save not in uploads but in uploads/category, how can I do it without duplicating the code?

What I need to change somewhere that the files that are sent to this route go to uploads/category

@Controller("category")
export class CategoryController
{
    @UseInterceptors(FileInterceptor("image"))
    @Post()
    async create(
        @UploadedFile(
            new ParseFilePipeBuilder()
                .addFileTypeValidator({ fileType: ALLOWED_IMAGE_TYPES.join() })
                .addMaxSizeValidator({ maxSize: MAX_FILE_SIZE_BYTES })
                .build({
                    fileIsRequired: false,
                    errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
                })
        )
        image
    )
    {
        console.log(image);
    }
}

2

Answers


  1. Yes, you can configure the code to store your files in the folder uploads/category, you need to specify that path configuration in your app.modules.ts file, following is the sample code as you’ve just provided MulterModule code in the question:

    @Module({
      imports: [
        ConfigModule.forRoot(),
        MulterModule.registerAsync({
          imports: [ConfigModule],
          inject: [ConfigService],
          async useFactory(configService: ConfigService) {
            const uploadFolder = configService.get<string>("uploadFolder");
    
            return {
              storage: diskStorage({
                destination: (req, file, cb) => {
                  const routePath = req.baseUrl;
                  let dynamicFolder = uploadFolder;
    
            //additionally you can add logic here for checking if the folder actually exists in the folder structure, if not then it can be handles further by throwing error or creating the folder
                  // here goes the logic of your folder :)
                  if (routePath.includes("category")) {
                    dynamicFolder = `${uploadFolder}/category`;
                  }
    
                  cb(null, dynamicFolder); 
                },
                filename: (req, file, cb) => {
                  const filename = `${Date.now()}-${file.originalname}`;
                  cb(null, filename); 
                },
              }),
            };
          },
        }),
      ],
      controllers: [CategoryController],
    })
    
    

    Hope this helps!

    Login or Signup to reply.
  2. Path Based Folder

    You can decide which folder to upload by passing a function to destination
    parameter :

    MulterModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      async useFactory(configService: ConfigService) {
        const baseUploadFolder = configService.get<string>('uploadFolder'); // Base folder from config
    
        return {
          storage: diskStorage({
            destination: (req, file, cb) => {
              // Add logic to determine folder dynamically
              const folder = req.path === "food" ? 'category/food' : 'default';
              const uploadFolder = `${baseUploadFolder}/${folder}`;
              
              // Ensure folder exists
              import('fs').then(fs => {
                if (!fs.existsSync(uploadFolder)) {
                  fs.mkdirSync(uploadFolder, { recursive: true });
                }
              });
    
              cb(null, uploadFolder);
            },
            filename: (req, file, cb) => {
              const filename = `${Date.now()}-${file.originalname}`;
              cb(null, filename);
            },
          }),
        };
      },
    });
    

    Using this you can apply check where to store files based upon the path you get request from user.

    Re-usable Multer Config way

    And if you want to handle this at controller level you can create a function to get multer configuration :

    import { diskStorage } from 'multer';
    import * as path from 'path';
    
    export function createMulterConfig(folder: string) {
      return {
        storage: diskStorage({
          destination: path.join(__dirname, '..', '..', 'upload', folder),
          filename: (req, file, cb) => {
            const filename = `${Date.now()}-${file.originalname}`;
            cb(null, filename);
          },
        }),
      };
    }
    
    

    In your controller, pass the specific folder name to the factory function and use it with FileInterceptor.

    import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
    import { FileInterceptor } from '@nestjs/platform-express';
    import { createMulterConfig } from './multer-config.factory';
    
    @Controller('category')
    export class CategoryController {
      @Post('default')
      @UseInterceptors(FileInterceptor('file', createMulterConfig('default')))
      uploadDefault(@UploadedFile() file: Express.Multer.File) {
        return { message: 'File uploaded to default folder', file };
      }
    
      @Post('category')
      @UseInterceptors(FileInterceptor('file', createMulterConfig('category')))
      uploadCategory(@UploadedFile() file: Express.Multer.File) {
        return { message: 'File uploaded to category folder', file };
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search