Ben Beri
Ben Beri

Reputation: 1201

nestjs multer get list of new file names after multer storage

I have this middleware that I use to upload files.

@Injectable()
export class FilesMiddleware implements NestMiddleware {

  private storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, path.join(__dirname, '../../uploads/'));
    },
    filename: (req, file, cb) => {
      let extArray = file.mimetype.split("/");
      let extension = extArray[extArray.length - 1];
      cb(null, file.fieldname + '-' + Date.now() + '.' + extension)
    }
});

  resolve(...args: any[]): MiddlewareFunction {
    return (req, res, next) => {
      console.log(req.files);
      const upload = multer({storage: this.storage});
      upload.any();
      return next();
    }
  }
}

The problem that in my request, when I use req.files it gives me the original file names instead of the new file names (with date, etc like I set in the multer storage options).

Is there a way I can get the new file names multer just uploaded with the middleware?

@Post('upload')
@UseInterceptors(FilesInterceptor('files[]', 20, {}))
public async onUpload(@Request() req, @Response() res, @UploadedFiles() files) {
    const mediaResponse = await this.media.saveMedias(0, files);
    res.json({status: true});
}

Upvotes: 8

Views: 6342

Answers (1)

Kim Kern
Kim Kern

Reputation: 60357

First of all: It does not make sense to both use multer via the built-in FilesInterceptor and a custom FilesMiddleware. Choose one of the following two options:

A) Use the built-in FilesInterceptor (recommended)

You can provide your storage configuration directly for each FilesInterceptor:

const storage = {...};

@Controller()
export class AppController {

  @Post('upload')
  @UseInterceptors(FilesInterceptor('files', 20, { storage }))
  public async onUpload(@UploadedFiles() files) {
    return files.map(file => file.filename);
  }
}

Or provide the default multer storage configuration by importing the MulterModule:

imports: [
  MulterModule.register({
    storage: {...},
  })
]

B) Using your own middleware (without FilesInterceptor)

Only use this if you need more flexibility than the FilesInterceptor provides. You can use a Promise to wait for the upload to finish. After the upload, you can access the new file names via req.files.

export class FilesMiddleware implements NestMiddleware {
  private storage = {...};

  async use(req, res, next) {
    const upload = multer({ storage: this.storage });
    // wait until upload has finished
    await new Promise((resolve, reject) => {
      upload.array('files')(req, res, err => err ? reject(err) : resolve());
    });
    // Then you can access the new file names
    console.log(req.files.map(file => file.filename));
    return next();
  }
}

Access the uploaded files in your controller via the request object:

@Post('upload')
public async onUpload(@Request() req) {
  return req.files.map(file => file.filename);
}

How to access the new file names?

You'll find the uploaded files in req.files (middleware) or @UploadedFiles() files (interceptor) as an array with the following structure:

[ { fieldname: 'files',
    originalname: 'originalname.json',
    encoding: '7bit',
    mimetype: 'application/json',
    destination: 'D:/myproject/src/uploads',
    // This is what you are looking for
    filename: 'files-1558459911159.json',
    path:
     'D:/myproject/src/uploads/files-1558459911159.json',
    size: 2735 } ]

Upvotes: 8

Related Questions