How to move multer upload midddleware to another file - node.js

Working with multer and gridFS for an express API I am developing. I am having trouble moving the upload object to another file. I have setup multer so that
export const upload = multer({
storage,
});
The following code works in index.ts where multer is initiated but not in any other routes file.
router.post("/upload", single("image"), (req, res) => {
const file = req.file;
if (!file) {
const error = new Error("Please upload a file");
res.send(error);
}
res.send(file);
});
It's not possible for me to post a whole snippet but I hope this is enough.
Cheers

I was actually able to solve this by adding the following:
app.use(
multer({
storage,
}).single("image")
);
Now that might mean it will run for every route which is another issue to address

you can do like this:
for all path
app.use('*', multer({storage}).single("images"));
just for post request
app.post('*',multer({storage}).single("images"))
For all post routes but a few routes
app.post('*',(req,res,next)=>{
const exceptionPaths = ["singup","login"]//don't upload
if(exceptionPaths.includes(req.path))return next()
next()
},multer({storage}).single("images"))

Related

Node/express - cancel multer photo upload if other fields validation fails

I have multer as middleware before editing user function. The thing is that multer uploads photo no matter what, so I am wondering if there is a way to somehow cancel upload if e.g. email is invalid. I tried to delete uploaded image through function via fs.unlink if there is validation error within edit function, but I get "EBUSY: resource busy or locked, unlink" error. I guess that multer uploads at the same time while I try to delete image.
Any ideas how to solve this?
on your function make a try/catch block and handle on error throw
import { unlink } from 'node:fs/promises';
import path from 'path'
// code ...
// inside your function
const img = req.file // this needs to be outside the try block
try {
// your code, throw on failed validation
} catch (e) {
if (img) {
// depends on where you store in multer middleware
const img_path = path.resolve(YOUR_PATH, img.filename)
await unlink(img_path);
console.log(`deleted uploaded ${ img_path }`);
}
// revert transaction or anything else
}
Nowadays, applications usually separates uploading file API from data manipulating API for some features like previewing/editing image. Later, they can run a background job to clean unused data.
But if it's necessary in your case, we can use multer's builtin MemoryStorage to keep file data in memory first, then save it to disk after validation completes.
const express = require('express');
const app = express();
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage });
const fs = require('fs');
app.post("/create_user_with_image", upload.single('img'), (req, res) => {
// Validation here
fs.writeFile(`uploads/${req.file.originalname}`, req.file.buffer, () => {
res.send('ok');
});
});
Note: as multer documentation said, this solution can cause your application to run out of memory when uploading very large files, or relatively small files in large numbers very quickly.

Multer gives unexpetcted end of form error

The file is being send to the nodejs server, but the upload.single gives an unexpected end of form error. How do i fix this?
const upload = multer({ dest: "../../uploaded_images" });
router.patch("/profile", upload.single("profileImage"), (req, res) => {
console.log(req.files) // This shows that there is a file named profileImage, I can see that when I remove the upload.single("profileImage")
res.send("")
})
the file structure:
It seems to be a bug in Multer itself. I solved by downgrading Multer to 1.4.3.
See https://github.com/expressjs/multer/issues/1144

Upload large file (>2GB) with multer

I'm trying to upload a large file (7GB) to my server. For this I'm using multer:
const express = require('express');
const multer = require('multer');
const {
saveLogFile,
} = require('../controller/log');
const router = express.Router();
const upload = multer();
router.post('/', upload.single('file'), saveLogFile);
In my saveLogFile controller, which is of format saveLogFile = async (req,res) => { ... } I want to get req.file. The multer package should give me the uploaded file with req.file. So when I try to upload small files (<2GB) It goes successfully. But when I try to upload files over 2GB, I get the following error:
buffer.js:364
throw new ERR_INVALID_OPT_VALUE.RangeError('size', size);
^
RangeError [ERR_INVALID_OPT_VALUE]: The value "7229116782" is invalid for option "size"
How can I bypass it? Actually, All I need is access for the uploaded file in my saveLogFile Controller.
The reason for this is probably that node will run out of memory as your using multer without passing any options. From the docs:
In case you omit the options object, the files will be kept in memory
and never written to disk.
Try using the dest or storage option in order to use a temporary file for the upload:
const upload = multer({ dest: './some-upload-folder' });
router.post('/', upload.single('file'), saveLogFile);

How to accept upload in multer only after approval from server?

I'm writing an application that accepts uploads from a client to server using electron, node and multer.
What I wanna do is only allow the upload after the server has accepted it. Maybe some kind of prompt. How would I go about it in JS?
Even though I mentioned multer, I imagine it's not gonna play a big part in this. Rn, my upload function goes through like this.
var upload = multer({ storage: storage, })
app.post('/uploadfile', upload.single('single'), (req, res, next) => {
const file = req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
res.send(file)
})
When the request comes, instead of running "upload.single", I imagine I have to use something else that prompts for validation and then run the actual upload function. But I'm very clueless. Any help is appreciated.

How do I get the body of a request from npm's multer if I don't upload a file?

I have a Node server using express.
I was originally using body-parser, but that doesn't allow for file uploads. So, I switched to multer (the easiest integration with express). However, in order to get any of the req (specifically req.body), this is my code:
var multer = require('multer');
var upload = multer({ dest : 'uploads/' });
server.all('/example', function (req, res, next) {
var up = upload.single('photo')
up(req, res, function(err) {
console.log(req.body); // I can finally access req.body
});
}
The problem with this, is that not all of my routes need to upload a file. Do I need to waste the CPU on calling upload.single() for each route in order to get access to the body? upload.single('') ends up not uploading any file, but it's still precious time spent on the main thread.
It appears that upload.single() waits for the callback, so it may not be as big of a deal as I'm making it, but I don't like calling functions when I don't have to.
Is there a way around calling upload.single(), or am I just making a bigger deal out of this than it really is?
For text-only multipart forms, you could use any of the multer methods, which are .single(), .array(), fields()
For instance using .array()
var multer = require('multer');
var upload = multer({ dest : 'uploads/' });
server.all('/example', upload.array(), function (req, res, next) {
console.log(req.body);
});
It doesn't really matter which you use, as long as it's invoked without arguments Multer will only parse the text-fields of the form for you, no files

Resources