How can I process a file only if criteria are met in a nodejs express like middleware style? #900
-
PROBLEM : Packages (multer, formidable, busboy...) usually store the file directly on the disk or memory with a custom validation in options. My problem is that, when I send fields & files at the same time, I don't want to waste resources on processing the entire file on the disk, or memory or even in a external storage like AWS S3, I want to stop everything and return an error to the client. I would like the following illustrated in the express route above : 1°) Get the file and fields metadata in a multipart request and attach them to the request object file : size + mimetype 3°) technologyController.createTechnology which does the following : If ok : Process the stream of the file & store it directly into AWS S3 (without it being store in memory or in the local disk) I can't figure out how to do it properly, it's been days. Code samples :
const formidable = require('formidable');
exports.getMetadata = (req, res, next) => {
const form = formidable({
uploadDir: `${__dirname}/../controllers/uploads`,
keepExtensions: true,
});
const filesInfos = [];
form.onPart = (part) => {
// I can filter here based on the mimetype but I don't have the information about the file size
// The formidable package doesn't include it
if (!part.mimetype) return form._handlePart(part);
filesInfos.push({ name: part.name, mimetype: part.mimetype })
};
form.parse(req, (err, fields, files) => {
// when parse() is called, files & fields are being processed already
});
return next();
};
const express = require('express');
const technologyController = require('../controllers/technologyController');
const multipart = require('../utils/multipart');
const validation = require('../utils/validation');
const router = express.Router();
router.route('/')
.post(
multipart.getMetadata, // get metadata from files & fields on multipart header
validation.technology, // validation with express-validator module
technologyController.createTechnology, // validate fields + files (size, mimetype) && create a record in database if ok
)
;
module.exports = router; Code samples are available in the public gist I made here : https://gist.github.com/bottom-up-ai/e411f3f7551261d15a93dbe1f459ed80 Thank you for your time and answers ! :) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 6 replies
-
There are conflicts in your requests: It is impossible to get all the metadata and also not store anything temporarily. Formidable is stream focused, so you can only know the file size as the file stream finishes, Also in the stream fields and files are not ordered. Imagine getting something https://github.com/node-formidable/formidable/blob/493ec88520c960d0d848d55a929630fde62f2aae/test/fixture/http/encoding/menu_separator.png.http |
Beta Was this translation helpful? Give feedback.
-
One option you might want to consider is to separate your front-end processing to send only the field data to the backend for some initial processing, then getting an all-clear message to send the rest. You should continue to do robust back-end verification as someone could work around the normal routine, but a two-step process might accelerate the common case (especially if it's common that the criteria aren't met) for good-faith users. |
Beta Was this translation helpful? Give feedback.
There are conflicts in your requests: It is impossible to get all the metadata and also not store anything temporarily.
Formidable is stream focused, so you can only know the file size as the file stream finishes,
if you don't want to upload as it is streaming in you have to store it or else the stream is lost.
Also in the stream fields and files are not ordered.
Imagine getting something https://github.com/node-formidable/formidable/blob/493ec88520c960d0d848d55a929630fde62f2aae/test/fixture/http/encoding/menu_separator.png.http
but times 5, and it is coming character by character