How to handle file upload in a Nodejs REST API project
It doesn’t matter if you are building a photosharing app like Instagram or a simple todo app — you might just find out that you need to upload a file — image, pdf, docx, etc. This post will walk you through 2 simple methods of handling file uploads in an Express Nodejs app.

One thing I love about Nodejs is that it allows us to use modules and packages by other developers to do most of our tasks. Uploading file is no different, there are three file upload modules I love especially, Multer, Multiparty and Formidable. I will be using multer for this post.
Let's start a new express app using the generator. Create a directory in your preferred location, let's call it express-uploads. Next cd in the created folder and run
npx express-generator
After successfully running this, run npm i to install the dependencies
npm i
You can test your express app at this point by visiting localhost:3000 in your browser and you should see the default express-generator page saying, Express welcome to express.
Time to install multer, run the code
npm i multer --save
Let's create a config folder in the root of the project and then create a multer.js file that will handle our multer configuration.
mkdir config && touch config/multer.js
In order to upload using multer, we will have to configure where on our server the file will be uploaded to — destination and the name of the file on our server. Open the multer.js file and write this
const multer = require('multer');const storage = multer.diskStorage({destination: (req, file, cb) => {cb(null, 'public/uploads')},filename: (req, file, cb) => {cb(null, Date.now()+'_'+file.originalname)}});const singleUpload = multer({storage: storage,limits: {fileSize: 1024 * 1024 }}).single('profile_pic');
module.exports = {singleUpload}
As you can on line 1, we required our multer dependency, to make it available, next we instantiated multer to a constant storage where we specified the destination to be ‘public/uploads’
destination: (req, file, cb) => {cb(null, 'public/uploads')
and also change the name of the file by concatenating the time it was uploaded to the original name, in this way users who have a file of the same name will not have issues when it is uploaded.
filename: (req, file, cb) => {cb(null, Date.now()+'_'+file.originalname)}
Next, we defined a single upload instance of the multer with the name of the upload field we are expecting — profile_pic in this case
multer.single('profile_pic');
We have also passed options to the multer singleUpload instance such as the max allowed file size — 1024 * 1024 (1MB). There are additional options such as filter for determining the type of file — pdf, jpeg, etc.
const singleUpload = multer({storage: storage,limits: {fileSize: 1024 * 1024 }}).single('profile_pic');
Next, we simply export it as a module
module.exports = {singleUpload}
Now let’s head over to our routes and add the upload function. Let’s add this in the users route. Open routes/user.js and change it to this
var express = require('express');var router = express.Router();const multerConfig = require('../config/multer')const userController = require('../controllers/users')router.post('/single-picture-upload', userController.uploadPic);module.exports = router;
Nothing much here except that we required our multerConfig, and I introduced the controller. You can create a controller by doing
mkdir controllers && touch controllers/users.js
Inside the controller will look like this
const multerConfig = require('../config/multer')
const multer = require('multer');async function uploadSingleFile(req,res){multerConfig.singleUpload(req, res, function(err) {if (err instanceof multer.MulterError) {return res.json(err.message);}else if (err) {
return res.json(err);
}else if (!req.file) {
return res.json({"image": req.file, "msg":'Please select an image to upload'});
}if(req.file){
return res.json({
'msg': 'uploaded',
'file':req.file});
}});}module.exports = {
uploadSingleFile
}
We have an uploadSingleFile function that calls the instance of the multerConfig we created earlier. We pass an anonymous function into it
multerConfig.singleUpload(req, res, function(err) {...}
and now have access to the uploaded file through multer via req.file.
if(req.file){
return res.json({
'msg': 'uploaded',
'file':req.file});
}
If you need to save to a db for example with sequelize, you can do
User.update(id:user,id, {profile_picture: req.file.path});
We can also use this to check for errors, by adding a new MulterError instance as seen. This means we have to require the multer dependency
if (err instanceof multer.MulterError) {return res.json(err.message);}
Before you are able to upload, you need to create the upload directory we specified earlier in the multer config. Now let us run the app and test our upload.
npm run start
In Postman, we will visit the Post route localhost:3000/users/single-picture-upload and click on ‘body’, choose ‘form-data’ and in the key enter ‘profile_pic’, hover over it and select file, click on “select files” and chose a file from your system and hit send. If all goes well you will see the response below
{"msg": "uploaded","file": {"fieldname": "profile_pic","originalname": "Screenshot 2020-11-30 at 14.00.48.png","encoding": "7bit","mimetype": "image/png","destination": "public/uploads","filename": "1606803452967_Screenshot 2020-11-30 at 14.00.48.png","path": "public/uploads/1606803452967_Screenshot 2020-11-30 at 14.00.48.png","size": 616178}}
Here is a link to the repo with the source code