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);
}
}
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.
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 };
}
}