File Handling with Multer
Introduction
My name is Nwobodo Chukwuebuka, and I am a beginner in web development. I started learning web development last year but haven't been consistent. I am a good learner, eager to gain knowledge and make an impact. I am passionate about what I do and always put in my best effort. However, I struggle with dedication and focus when no one is supervising me. That's why I registered for HNG11, as I want to complete my web development course and need challenges, guidance, and mentorship to do so.
I hope that by the end of the HNG class, I'll be a good web developer and data analyst, even though I currently have little knowledge of data analysis.
To improve my backend development skills, I built a profile generator that allows people to create a beautiful profile by entering their public name, preferred username, and a public bio of up to 150 words.
However, I encountered a roadblock when it came to handling the files that needed to be uploaded.
The challenge
I wondered how to stop people from uploading large files or files that aren't images. I needed to check that the uploaded image is really a picture and that it doesn't go over 2MB. This helps keep storage costs low as the product grows.
My Solution
Initially, I used to upload files without any checks, but considering the challenge mentioned above, I needed a solution. I did some research and discovered a package called Multer, which is a Node.js middleware for handling multipart/form-data, primarily used for uploading files.
Setup
First I installed multer.
npm install express multer
Import Multer
Then I import multer into my code
const multer = require('multer');
Setup the function that implements multer
Then I setup limits on the files size and filter the files to ensure it is an image and a single picture using multer.
const validateAndUpload = multer({
limits: { fileSize: 2 * 1024 * 1024 }, // 2MB
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed!'), false);
}
}
}).single('picture');
Application
Implementing this within my endpoint
app.post('/create-profile', validateAndUpload, (req, res) => {
const { publicName, preferredUsername, publicBio } = req.body;
// as you see from above by calling this post method, we also employ the
//validateAndUpload function that we created initially which returns a true
//if what we received from the user is what we are looking for
if (!req.file) {
return res.status(400).json({ error: 'Picture is required and must be an image less than 2MB' });
}
//this is what handles the response when the profle s creed successfully
res.status(200).json({
message: 'Profile created successfully',
profile: {
publicName,
preferredUsername,
publicBio,
picture: req.file.filename
}
});
});
// This is meant to hadle whatever errors that come up while uploading
//it is more like a checker before any other thing is done.
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
return res.status(400).json({ error: err.message });
}
if (err) {
return res.status(500).json({ error: err.message });
}
next();
});
This way when someone uploads an image I can check the file type and the image size as well.
Finally
This is how the code looks at the end.
const express = require('express');
const multer = require('multer');
const app = express();
const port = 3000;
const validateAndUpload = multer({
limits: { fileSize: 2 * 1024 * 1024 },
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed!'), false);
}
}
}).single('picture');
app.use(express.json());
app.post('/create-profile', validateAndUpload , (req, res) => {
const { publicName, preferredUsername, publicBio } = req.body;
if (!req.file) {
return res.status(400).json({ error: 'Picture is required and must be an image less than 2MB' });
}
res.status(200).json({
message: 'Profile created successfully',
profile: {
publicName,
preferredUsername,
publicBio,
picture: req.file.filename
}
});
});
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
return res.status(400).json({ error: err.message });
}
if (err) {
return res.status(500).json({ error: err.message });
}
next();
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
References
Below are useful links
Learn about the multer package
Thanks for your time. Hope you enjoyed it. Feel free to comment and join my newsletter to keep yourself up-to-date with future release.
~OracleJnr
Subscribe to my newsletter
Read articles from chukwuebua Emmanuel Nwoboodo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by