As we know, nowadays file uploading is a very common and basic feature that almost every website may needs. In this tutorial, we'll get to know how to handle file upload scenarios.
For that scenario, I'm going to use a common npm module named "Multer".
What is Multer?
According to npm documentation:
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is written on top of the busboy for maximum efficiency.
You can visit npm Multer documentation for more information.
Getting Started
Follow the step-by-step guide to learn about how can we upload files using Multer in Node.JS and Express:
Step 1: Let's first create a directory namely "multer_file_upload" and initialize that directory using the following command:
- mkdir multer_file_upload
- cd multer_file_upload
- npm init -y
Step 2: Installing needed dependencies:
For creating the server I'm using express and for file operation, I'm using Multer as I already mentioned. I'm going to install two other npm modules i.e., "nodemon" and "path" along with these modules.
Let's install them using the following command:
npm install express multer path --save
npm install nodemon --save-dev
After installing these npm modules. Your "package.json" file will look like this.
{ "name": "multer_file_upload", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon index.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.18.1", "multer": "^1.4.5-lts.1", "path": "^0.12.7" }, "devDependencies": { "nodemon": "^2.0.19" } }
Step 3: Setting up the Server
For setting up the server. Let's first create our server file name "index.js". You can create a file using the following command or with the help of widgets too.
touch index.js
After creating the file just type the following code for setting up the server.
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Server is running at ${PORT} port`)
})
Let's run this code using the following command:
npm start
When you run your code. It'll produce an output like this
[nodemon] 2.0.19[nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node index.js` Server is running at 3000 port
CONGRATULATIONS.....You've successfully set up your Server.
Step 4: Configure the Storage folder
After successfully setting up the server. Let's configure the storage folder where we're going to store our uploading documents.
We can configure auto folder creation in case the folder doesn't exist using the npm fs module. There are several functions available in the fs module which help us to maintain the file system.
For more information, you can visit fs documentation and for function, you can visit fs functions.
Let's install the fs module using the following command:
npm install fs --save
After installing the fs module. Let's configure auto folder creation in case the folder doesn't exist.
For that scenario, copy the following code
const fs = require('fs')...
// getting the path for upload folder const fileUploadingFolder = __dirname + "/uploads";...// check is folder exist if not then create folder if (!fs.existsSync(fileUploadingFolder)) { fs.mkdirSync(fileUploadingFolder) }
Step 5: Configure Route
After configuring the fs module for folder creation. Let's configure the route where we're going to configure our multer.
For that purpose, I'm going to create two new folders for storing routing and their corresponding controller i.e., routes and controller. And both folders may store "index.js" for routing and their corresponding controller function.
Let's copy the following code inside the server file i.e., "index.js" which includes all the routes into our app.
Copy the following code just above the "app.listen" line.
app.use('/', require('./routes'))
After adding the route file to the server file. Let's configure them. For that scenario, I'm going to do some changes inside the "index.js" file of the routes folder. Let's copy the following code inside your file.
const router = require('express').Router()
const Controller = require('../Controller')
router.get('/', Controller.homecontroller)
module.exports = router
I've added the Controller file too. So, here are the changes to the controller's "index.js" file.
const homecontroller = async (req, res, next) => { try { res.status(200).send('Welcome to Home Page Controller !!') } catch (error) { next(error) } }; module.exports = { homecontroller };
When you hit the following route "http://localhost:3000/". You'll get the following output.
Step 6: Configure Multer with route
Let's first require the Multer module inside our routes "index.js" file and configure them along with their route.
The next thing will be to define a storage location for our files. Multer gives the option of storing files either in memory(multer.memoryStorage) or on disk(memory.diskStorage). For this project, I'm going to use disk storage.
Let's first start with single file uploading.
const multer = require('multer') // for storage const storageForDocs = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "uploads/") }, filename: function (req, file, cb) { cb(null, Date.now() + path.extname(file.originalname)) } }) // for uploading single files const uploadFile = multer({ storage: storageForDocs }).single("image")
// for single file route router.post('/singleupload', (req, res, next) => { uploadFile(req, res, (err) => { if (err) { res.send({ error: true, ...err }) } else { if (req.file == undefined) { res.send({ error: true, message: "Error: No File Selected!!" }) } else { next() } } }) }, Controller.singleUploadController)
The corresponding controller file changes for singleUploadController and adds to the "module.exports" too.const singleUploadController = async (req, res, next) => {
try {
const file = req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
res.status(200).json({
error: false,
message: 'File uploaded successfully',
fileData: file
})
} catch (error) {
next(error)
}
};
module.exports = { ...
singleUploadController};
const singleUploadController = async (req, res, next) => { try { const file = req.file if (!file) { const error = new Error('Please upload a file') error.httpStatusCode = 400 return next(error) } res.status(200).json({ error: false, message: 'File uploaded successfully', fileData: file }) } catch (error) { next(error) } };
module.exports = { ...
singleUploadController};
When we hit "http://localhost:3000/singleupload" with having "image" key and their corresponding single value. It'll produce the following output.
In some cases, we've to upload many files then in that case we'll use a different method instead of the "single" method which you can view at Multer.
Currently, I'm going to use the "array" method for uploading multiple files. This function may provide the data in the form of a buffer. We've to convert all files from that buffer and store them in our preferred location.// for uploading multiple file
const multipleStorage = multer.memoryStorage();
const uploadMultiple = multer({
storage: multipleStorage
})
// for multiple files
router.post('/mutlipleupload', uploadMultiple.array('myFiles', 4), Controller.mutlipleUploadController)
// for uploading multiple file const multipleStorage = multer.memoryStorage(); const uploadMultiple = multer({ storage: multipleStorage }) // for multiple files router.post('/mutlipleupload', uploadMultiple.array('myFiles', 4), Controller.mutlipleUploadController)
The controller for that multiple files.
const mutlipleUploadController = async (req, res, next) => { try { const file = req.files if (!file) { const error = new Error('Please upload a file') error.httpStatusCode = 400 return next(error) } res.status(200).json({ error: false, message: 'File uploaded successfully', fileData: file }) } catch (error) { next(error) } };
module.exports = { ... mutlipleUploadController };