Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

531
Vistas
Formidable: Parse multipart/form-data request THEN upload file

I have a problem since yesterday with my node express app.

The thing what I want to do is the next one:

Middleware 1, step 1 (parse request): Parse the multipart/form-data in req.body with formidable and do what I want to do with the data (such validation), then go to step 2 if all being good.

Middleware 2, step 2 (upload file): Upload file with formidable (already being parsed)

Problems:

  • Multer: Already tested with Multer but impossible, I have to put the middleware 2 before the middleware 1 otherwise the req.body is empty (also tested multer.none()).
  • Formidable: Actively testing with formidable but when I parse the request in the Middleware 1, formidable won't do anything in the Middleware 2 (because my req.body is already parsed and he didn't find the file ?)

I know there is a filter function but I really want to have two seperated middlewares.

Express middlewares

const formidable = require('formidable');

// parse request
module.exports.middleware1 = async (req, res, next) => {
  const form = formidable({ multiples: true });

  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    
    // request parsed
    // do what I want to do with the fields (such validation)
    console.log(fields)
    
    next()
  });
}

// upload file
module.exports.middleware2 = async (req, res, next) => {
  const options = {
    uploadDir: 'test',
    keepExtensions: true,
    maxFiles: 1,
    filename: function (name, ext, part, form) {
      return name
    },
    filter: function ({name, originalFilename, mimetype}) {
      return true
    }
  }
  const form = formidable(options);
  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    
    // file uploaded, go to controller
    
    next()
  });
}

Front app

publishPost: function () {
  let formData = new FormData()

  const post = {
    filters: {
      ...this.postFilters
    },
    details: {
      ...this.postDetails
    }
  }

  formData.append('post', JSON.stringify(post))
  formData.append('file', this.postMedia.file)

  postService.createOne(formData).then((res) => {
    if (res) {
      postServiceStatus.createOneDone()
    }
  });
}

If anyone has an idea, I'd be grateful!

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

I finally found a solution to my problem !

I created a global error handler that handle all the errors on my API, and when an error is related to my route where I created the file (in the first middleware), I delete the file with informations passed in req.file.

const fs = require('fs')
const { DEFAULT_API_PATH } = process.env

/**
 * Handle middlewares errors
 * @param {Object} err error object
 * @param {String} err.type type of error (service affected by the error)
 * @param {String} err.error original error
 * @param {String} err.message returned error
 * @param {Number} err.status error status
 * @returns 
 */
module.exports = async (err, req, res, next) => {
  if (err.error) console.log(err.error) 
  
  // Delete file
  if (req.path === `${DEFAULT_API_PATH}/posts/create` && req.file) {
    if (fs.existsSync(req.file.path)) {
      fs.unlinkSync(req.file.path, function (err) {
        console.log(err)
      }); 
    }
  } 
  
  if (err.type && err.type === 'database') return res.status(err.status || 400).send({ error: err.message || 'Une erreur innatendue s\'est produite avec la base de données. Veuillez réessayer dans un instant.' }) 
  else if (err.type && err.type === 'server') return res.status(err.status || 400).send({ error: err.message || 'Une erreur innatendue s\'est produite avec le serveur. Veuillez réessayer dans un instant.' }) 
  
  return res.status(err.status || 400).send({ error: err.message || 'Une erreur innatendue s\'est produite. Veuillez réessayer dans un instant.' }) 
}
over 4 years ago · Santiago Trujillo Denunciar

0

The server can consume an incoming request only once, because the request body is streamed by the client and the HTTP protocol does not allow the server to request a "rewind" from the client.

The idea of multer and formidable is to write the file to the uploadDir as the request is being consumed. If you do not want to do that in the first middleware, you need to store the file in a Javascript variable (for example, res.locals.uploadedFile) and write it to the uploadDir yourself in the second middleware. But what would be the advantage of that? Main memory is more expensive than disk space.

Why do you insist on two separate middlewares?

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda