Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload file using nestjs and multer

Tags:

nestjs

Since nestjs is an express app, it's possible to use any library to handle upload using nest, and since it provides Midlewares, it's also possible to use multer. My question is: What's the best way to handle file uploads using nestjs?

like image 846
Victor Ivens Avatar asked Mar 04 '18 13:03

Victor Ivens


2 Answers

As informed by @Kamyl on issue https://github.com/nestjs/nest/issues/262, since v4.6.0 is possible to upload files using multer to nestjs using a common file interceptor.

import { ... , UseInterceptors, FileInterceptor, UploadedFile } from '@nestjs/common'

... 

@UseInterceptors(FileInterceptor('file'))
async upload( @UploadedFile() file) {
  console.log(file)
}

This way the variable file will have a buffer


Using Multer options

It's also needed the field name as the first param, then an array with Multer Options

import { ... , UseInterceptors, FileInterceptor, UploadedFile } from '@nestjs/common'
import { diskStorage } from 'multer'
import { extname } from 'path'

...

@UseInterceptors(FileInterceptor('file', {
  storage: diskStorage({
    destination: './uploads'
    , filename: (req, file, cb) => {
      // Generating a 32 random chars long string
      const randomName = Array(32).fill(null).map(() => (Math.round(Math.random() * 16)).toString(16)).join('')
      //Calling the callback passing the random name generated with the original extension name
      cb(null, `${randomName}${extname(file.originalname)}`)
    }
  })
}))
async upload( @UploadedFile() file) {
  console.log(file)
}

This way the variable file will have a filename, destination and path.

The destination param from the diskStorage can also be a function, with the parameters and expecting the callback the same as filename. By passing a diskStorage the file will be automatically saved to the destination informed with the filename given.

It's also possible to handle multiple files by using @UploadedFiles and FilesInterceptor (plural)

like image 200
Victor Ivens Avatar answered Oct 16 '22 11:10

Victor Ivens


A cleaner way would be to extract the configurations to a separate file and then call it inside the interceptor method

import { extname } from 'path';
import { existsSync, mkdirSync } from 'fs';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';

// Multer configuration
export const multerConfig = {
    dest: process.env.UPLOAD_LOCATION,
};

// Multer upload options
export const multerOptions = {
    // Enable file size limits
    limits: {
        fileSize: +process.env.MAX_FILE_SIZE,
    },
    // Check the mimetypes to allow for upload
    fileFilter: (req: any, file: any, cb: any) => {
        if (file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) {
            // Allow storage of file
            cb(null, true);
        } else {
            // Reject file
            cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false);
        }
    },
    // Storage properties
    storage: diskStorage({
        // Destination storage path details
        destination: (req: any, file: any, cb: any) => {
            const uploadPath = multerConfig.dest;
            // Create folder if doesn't exist
            if (!existsSync(uploadPath)) {
                mkdirSync(uploadPath);
            }
            cb(null, uploadPath);
        },
        // File modification details
        filename: (req: any, file: any, cb: any) => {
            // Calling the callback passing the random name generated with the original extension name
            cb(null, `${uuid()}${extname(file.originalname)}`);
        },
    }),
};

and then call it under the interceptor like so

import { ... , UseInterceptors, FileInterceptor, UploadedFile } from '@nestjs/common'
import { diskStorage } from 'multer'
import { extname } from 'path'
import { multerOptions } from 'src/config/multer.config';
...

@Post('/action/upload')
@UseInterceptors(FileInterceptor('file', multerOptions))
async upload( @UploadedFile() file) {
  console.log(file)
}
like image 25
Sandeep K Nair Avatar answered Oct 16 '22 09:10

Sandeep K Nair