Extract ZIP file before saving it's contents to multer

Viewed 886

I have a express-like REST API and I enabled file upload throughout multer.

My file upload-related logic is all addressed within multer, and I'd like to keep it that way. Recently a new file-type was going to be be added to this endpoint (.zip), but I dont really want to save it. I want to be able to re-use multer's logic that was already implemented, but add a precedent step, to pass the files to multer, so it can save them and complete the flow as usual.

What I have so far:

routes.post(
  '/upload',
  multer(multerConfig).single('file'),
  async (req, res) => {
    const { path: filePath } = req.file

    const file = xlsx.readFile(filePath)
    const cells = Object.values(file.Sheets).reduce((accumulator, sheet) => {
      const sheetCellsKeys = Object.keys(sheet)

      const sortedCellsKeys = sheetCellsKeys
        .sort((previousCell, currentCell) => (
          previousCell.localeCompare(currentCell, 'en', { numeric: true })
        ))

      const validCellsKeys = sortedCellsKeys.filter((cellKey) => (
        /^[A-Z]+[0-9]+$/.test(cellKey)
      ))

      const grouppedCellsKeys = groupBy(validCellsKeys, (cellKey) => (
        cellKey.replace(/\D/g, '')
      ))

      return [
        ...accumulator,
        ...Object.values(grouppedCellsKeys)
          .reduce((cellsAccumulator, cellsKeys) => ([
            ...cellsAccumulator,
            cellsKeys.map((cellKey) => (
              sheet[cellKey].v
            )),
          ]), []),
      ]
    }, [])

    res.send(cells)
  },
)

I want to decompress my zip file, and pass it to multer, as if it's contents was sent to the /process endpoint. Is that possible?

1 Answers

I don't know how to update the value of multer. But in this case, I will create a middleware function, and set it in after of multer middleware, in this middleware I will extract the zip file, and save the content of zip file to storage folder, finally, pass the new file path to next process via req.file object (because in the last process you just need path of the excel file).

The below code just is an example for my idea:

New middleware

const unzipMiddleware = (req, res, next) => {
  const { path: zipFilePath, mimetype } = req.file // zipFilePath is './public/uploads/file.zip'
  if (mimetype !== 'application/gzip') { // You would want to check that, I think so
    return next() // do nothing
  }
  // get content of the zipFilePath [1.xlsx, 2.xlsx, 3.xlsx,....]
  // extract the zip file to storage path (maybe the same with multer setting - ./public/uploads/)

  // update the value of the file info
  req.file = {
    path: './public/uploads/3.xlsx' // example, you just use the last file
  }

  next() // continue, important line
}

Usage of new middleware

routes.post(
  '/upload',
  multer(multerConfig).single('file'),
  unzipMiddleware, // use new middleware here, after multer middleware
  async (req, res) => {
    const { path: filePath } = req.file // now filePath will be './public/uploads/3.xlsx', instead of './public/uploads/file.zip'
    //... your logic
  }
)
Related