Day 8: Storing Data Securely and Implementing File Uploads


In this tutorial, you’ll learn how to implement secure file uploads in your Express API, store files in your local file system or cloud storage, and secure the process of uploading sensitive user data. By the end of today’s lesson, users will be able to upload files securely to your API.


What You Will Learn Today:

  1. Setting up file uploads using Multer
  2. Storing uploaded files securely
  3. Validating file types and sizes
  4. Implementing secure file storage (local or cloud)
  5. Testing file uploads using Postman

Step 1: Setting Up File Uploads Using Multer

To handle file uploads in Express, we’ll use Multer, a middleware for handling multipart/form-data, which is primarily used for uploading files.

Installing Multer

  1. Install Multer by running the following command:
npm install multer

Setting Up Multer

  1. Inside your project directory, create a new folder called uploads where uploaded files will be stored:
mkdir uploads
  1. Now, let’s configure Multer in index.js to handle file uploads. Open index.js and add the following code:
const express = require('express');
const https = require('https');
const fs = require('fs');
const multer = require('multer');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 5000;

// Configure Multer for file storage
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/'); // Uploads will be stored in the 'uploads' folder
  },
  filename: function (req, file, cb) {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
  }
});

const upload = multer({ storage: storage });

// Example route for file uploads
app.post('/upload', upload.single('file'), (req, res) => {
  res.json({ message: 'File uploaded successfully', file: req.file });
});

// Start the server
app.listen(PORT, () => {
  console.log(`Secure server running on https://localhost:${PORT}`);
});

Explanation:

  • multer.diskStorage(): Configures Multer to store files locally in the uploads folder. Each file is given a unique name using the current timestamp and a random number.
  • upload.single(‘file’): Middleware for handling single file uploads. The form field name must match the string passed to upload.single().
  • path.extname(): Extracts the file extension from the original filename, so the uploaded file retains its original file extension.
See also  Working with Multiple Database Connections in Laravel

Step 2: Validating File Types and Sizes

To ensure that only valid file types (e.g., images) are uploaded, we’ll add validation to the Multer configuration.

  1. Open index.js and update the Multer configuration with validation:
// Configure Multer for file storage with validation
const fileFilter = (req, file, cb) => {
  // Accept images only (jpg, jpeg, png)
  if (!file.mimetype.startsWith('image/')) {
    return cb(new Error('Invalid file type, only images are allowed!'), false);
  }
  cb(null, true);
};

const upload = multer({
  storage: storage,
  fileFilter: fileFilter,
  limits: { fileSize: 5 * 1024 * 1024 } // Limit file size to 5MB
});

// Example route for file uploads
app.post('/upload', upload.single('file'), (req, res) => {
  res.json({ message: 'File uploaded successfully', file: req.file });
});

Explanation:

  • fileFilter: Checks the MIME type of the uploaded file and ensures that only image files (e.g., jpg, png) are accepted.
  • limits.fileSize: Sets a maximum file size limit of 5MB. If the file exceeds this size, Multer will throw an error.

Step 3: Implementing Error Handling for File Uploads

Let’s add proper error handling for invalid file types or sizes.

  1. Modify the upload route to catch and handle errors:
app.post('/upload', (req, res, next) => {
  upload.single('file')(req, res, (err) => {
    if (err) {
      // Handle file upload errors
      return res.status(400).json({ message: err.message });
    }
    res.json({ message: 'File uploaded successfully', file: req.file });
  });
});

Explanation:

  • If there is an error (e.g., invalid file type or file too large), we return a 400 Bad Request response with the error message.
  • If the upload is successful, we send a success message along with the uploaded file details.

Step 4: Storing Files Securely in Cloud Storage (Optional)

Instead of storing files locally, you might want to store them in cloud storage like AWS S3 for better scalability and security.

See also  Day 6: Securing Your API with HTTPS and Environment Variables

Using AWS S3 for File Uploads

  1. Install the aws-sdk package:
npm install aws-sdk
  1. In your .env file, add your AWS credentials:
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_BUCKET_NAME=your_bucket_name
AWS_REGION=your_region
  1. Modify your file upload configuration to upload files directly to S3:
const AWS = require('aws-sdk');
const multerS3 = require('multer-s3');

// Configure AWS S3
const s3 = new AWS.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  region: process.env.AWS_REGION,
});

// Configure Multer to use S3 for file storage
const upload = multer({
  storage: multerS3({
    s3: s3,
    bucket: process.env.AWS_BUCKET_NAME,
    acl: 'public-read', // Set the file to be publicly accessible
    key: function (req, file, cb) {
      const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
      cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
    }
  }),
  fileFilter: fileFilter,
  limits: { fileSize: 5 * 1024 * 1024 } // Limit file size to 5MB
});

// Example route for file uploads
app.post('/upload', upload.single('file'), (req, res) => {
  res.json({ message: 'File uploaded successfully', file: req.file.location });
});

Explanation:

  • multerS3: This is used to configure Multer to store files in an S3 bucket instead of the local file system.
  • file.location: The S3 URL where the uploaded file can be accessed.

Step 5: Testing File Uploads with Postman

Now that we’ve configured file uploads, let’s test the file upload functionality using Postman.

1. Testing Local File Uploads

  1. Open Postman and create a new POST request to http://localhost:5000/upload.
  2. In the Body tab, select form-data.
  3. Add a key called file, select File as the type, and upload an image file.
  4. Click Send.

If successful, you should receive a response similar to:

{
  "message": "File uploaded successfully",
  "file": {
    "fieldname": "file",
    "originalname": "example.jpg",
    "encoding": "7bit",
    "mimetype": "image/jpeg",
    "destination": "uploads/",
    "filename": "file-1638317236431-933414805.jpg",
    "path": "uploads/file-1638317236431-933414805.jpg",
    "size": 128742
  }
}

2. Testing Invalid File Types

  1. Try uploading a file with an invalid type (e.g., a text file).
  2. You should receive an error response like this:
{
  "message": "Invalid file type, only images are allowed!"
}

3. Testing File Upload to AWS S3

If you’re using AWS S3, you should receive a response with the file’s S3 URL:

{
  "message": "File uploaded successfully",
  "file": "https://your-bucket.s3.amazonaws.com/file-1638317236431-933414805.jpg"
}

Step 6: Recap and Summary

In this tutorial, you learned how to securely implement file uploads in your Express API. Here’s a quick summary of what you’ve done:

  • Installed and configured Multer to handle file uploads.
  • Validated file types and sizes to prevent malicious uploads.
  • Implemented error handling for invalid file uploads.
  • Configured AWS S
See also  Day 3: Adding Navigation Between Screens Using React Navigation

3 for cloud-based file storage (optional).

  • Tested file uploads using Postman.

With file uploads now implemented, users can securely upload images, documents, or other files to your API.


Next Up: Day 9 – Implementing Pagination and Filtering in Your API

In Day 9, we’ll focus on implementing pagination and filtering to optimize the way you retrieve and present large datasets in your API.

Stay tuned for more advanced features tomorrow!


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.