Upload file with File Size and Type Validation in express JS and MongoDB


When handling file uploads in an Express.js application, it’s important to validate the file size and type to ensure that users only upload files that are acceptable for your application. This validation helps protect your application from potential security risks and ensures that only files of a specific type and size are processed.

Here’s how to implement file size and type validation using multer in an Express.js application with MongoDB:

1. Set Up Your Project

  1. Initialize Your Project:

    If you haven't already, set up your project and install the necessary packages:

    mkdir express-file-upload cd express-file-upload npm init -y npm install express mongoose ejs multer
    • express: Web framework for Node.js.
    • mongoose: ODM for MongoDB.
    • ejs: Templating engine.
    • multer: Middleware for handling file uploads.
  2. Create Basic File Structure:

    express-file-upload/ ├── models/ │ └── Item.js ├── views/ │ ├── index.ejs │ └── upload.ejs ├── app.js └── uploads/ (This directory will store uploaded files)

2. Define the Mongoose Model

Create a model to store information about uploaded files.

models/Item.js

const mongoose = require('mongoose'); const itemSchema = new mongoose.Schema({ name: { type: String, required: true }, description: String, filePath: String // Path to the uploaded file }); const Item = mongoose.model('Item', itemSchema); module.exports = Item;

3. Configure Multer with Validation

Multer allows you to set limits and filter file types. You can configure it to handle file size and type validation.

app.js

const express = require('express'); const mongoose = require('mongoose'); const path = require('path'); const multer = require('multer'); const bodyParser = require('body-parser'); const Item = require('./models/Item'); const app = express(); // Connect to MongoDB mongoose.connect('mongodb://localhost:27017/file-upload', { useNewUrlParser: true, useUnifiedTopology: true }).then(() => { console.log('Connected to MongoDB'); }).catch(err => { console.error('Failed to connect to MongoDB', err); }); // Middleware app.use(bodyParser.urlencoded({ extended: true })); app.use(express.json()); // Set EJS as the view engine app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); // Configure Multer const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'uploads/'); // Directory to save files }, filename: (req, file, cb) => { cb(null, Date.now() + path.extname(file.originalname)); // Unique filename } }); // File filter for type validation const fileFilter = (req, file, cb) => { const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf']; if (allowedTypes.includes(file.mimetype)) { cb(null, true); // Accept the file } else { cb(new Error('Invalid file type. Only JPEG, PNG, and PDF are allowed.'), false); // Reject the file } }; // File size limit (e.g., 2 MB) const limits = { fileSize: 2 * 1024 * 1024 }; const upload = multer({ storage: storage, fileFilter: fileFilter, limits: limits }); // Routes app.get('/', async (req, res) => { try { const items = await Item.find(); res.render('index', { items }); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); app.get('/upload', (req, res) => { res.render('upload'); }); app.post('/upload', upload.single('file'), async (req, res) => { try { // Handle validation errors if (req.fileValidationError) { return res.status(400).send(req.fileValidationError); } if (!req.file) { return res.status(400).send('No file was uploaded.'); } const newItem = new Item({ name: req.body.name, description: req.body.description, filePath: req.file.path // Save file path in the database }); await newItem.save(); res.redirect('/'); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // Static files (for serving uploaded files) app.use('/uploads', express.static('uploads')); // Error handling middleware app.use((err, req, res, next) => { if (err instanceof multer.MulterError) { // Multer-specific errors res.status(500).send(err.message); } else if (err) { // Other errors res.status(500).send(err.message); } }); // Start the server app.listen(3000, () => { console.log('Server running on http://localhost:3000'); });

4. Create EJS Templates

  1. Create views/index.ejs:

    This template displays a list of uploaded files and their details.

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Uploaded Files</title> </head> <body> <h1>Uploaded Files</h1> <a href="/upload">Upload New File</a> <ul> <% items.forEach(item => { %> <li> <strong><%= item.name %></strong>: <%= item.description %> <br> <a href="/uploads/<%= path.basename(item.filePath) %>">View File</a> </li> <% }) %> </ul> </body> </html>
  2. Create views/upload.ejs:

    This template provides a form for uploading new files.

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Upload File</title> </head> <body> <h1>Upload New File</h1> <form action="/upload" method="POST" enctype="multipart/form-data"> <label for="name">Name:</label> <input type="text" id="name" name="name" required> <br> <label for="description">Description:</label> <textarea id="description" name="description"></textarea> <br> <label for="file">File:</label> <input type="file" id="file" name="file" required> <br> <button type="submit">Upload File</button> </form> <a href="/">Back to List</a> </body> </html>

5. Test the File Upload

  1. Start the Server:

    Run your application:

    node app.js
  2. Upload a File:

    • Go to http://localhost:3000/upload and use the form to upload a file.
    • The server will validate the file size and type based on the Multer configuration.
  3. Error Handling:

    • If a file is not of an allowed type or exceeds the size limit, an appropriate error message will be shown.
    • Check the uploads directory and MongoDB database to ensure the file and its metadata are correctly saved.

Summary

  1. Project Setup: Initialize your project and install dependencies.
  2. Mongoose Model: Define a model to store file metadata.
  3. Multer Configuration: Configure Multer for file size and type validation.
  4. EJS Templates: Create templates for displaying and uploading files.
  5. Testing: Verify that file uploads are validated and handled correctly.