Upload Images to AWS S3 from Node Server w/ Multer

  1. Create a bucket
    1. (Sign in to console) Sign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/.
    2. Choose Create Bucket
    3. In Bucket name,  enter a DNS-compliant name for your bucket.
    4. In Region, choose the AWS Region where you want the bucket to reside.
    5. In Bucket settings for Block Public Access, keep the values set to the defaults. They will be private for now. We will change them to public later.
    6. Choose Create bucket.

2. Get security credentials

3. Install dependencies to Node project

npm i --save aws-sdk multer multer-s3

4. Set up the file upload middleware with multer and AWS-SDK

const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');

const config = require('../config');

aws.config.update({
   secretAccessKey: config.get('AWS_SECRET_ACCESS'),
   accessKeyId: config.get('AWS_ACCESS_KEY'),
   region: 'us-east-1'
});

const s3 = new aws.S3();

const upload = multer({
   storage: multerS3({
      s3,
      bucket: 'bucket-name',
      acl: 'public-read',
      key: function (req, file, cb) {
         cb(null, Date.now().toString())
      }
   })
}).single('photo');

module.exports = upload;

In the upload middleware, we define a key value. This key serves essentially as the image’s name in AWS, differentiating images in the list in the AWS Console. We are setting the key to the date at which the image is saved.

5. Set up route to handle image requests

router.post('/image-upload', function(req, res) {
   upload(req, res, (err) => {
      if (err) {
         return res.status(422).send({errors: [{title: 'File Upload Error', detail: err.message}] });
      }

      return res.json({'imageUrl': req.file.location});
   });
});

6. Set permissions to public

7. Send request in Postman to test it

8. Check the AWS S3 console to see if a new entry is there

The Date string that we set as the key value is in the Name field.

Uploading Images in Node with Multer

Multer is one of the most popular libraries for uploading files to a Node.js server. Multer is a Node.js middleware for handling multipart/form-data, which is primarily used for uploading files.

Install Multer package in your project

npm i multer

Create a form in your HTML file that will post to your server. Notice the enctype is set to multipart/form-data. Also, make sure to give your inputs names. That is how Multer finds them.

<form action="/" method="POST" enctype="multipart/form-data">
   <input type="text" name="name">
   <input type="file" name="image">
   <button type="submit">Submit</button>
</form>

Below is a very basic application of Multer. When our form makes a post request to the root, the Multer middleware (upload.single('image')) will give us access to the inputs in the request. The middleware takes in the name of the file input from your form. In our case, we called the input image. req.file holds the file uploaded to the form. req.body holds the text inputs.

When we defined our upload middleware, we set the destination in which we want to store our file uploads from Multer. In this case, files from our form will be stored in the uploads folder. If the folder doesn’t exist, it will be created automatically.

var express = require('express')
var multer  = require('multer')
var upload = multer({ dest: 'uploads/' })

var app = express()

app.post('/', upload.single('image'), function (req, res, next) {
  console.log(req.file, req.body);
})

Multer also allows us to customize the way that we handle file uploads.

The disk storage engine gives you full control on storing files to disk. There are two options available, destination and filename. They are both functions that determine where the file should be stored.

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
       cb(null, './public/uploads');
    },
    filename: function (req, file, cb) {
        cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
    }
});

You append this storage property to your upload middleware

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

You can also create a filter function to define which types of files you want to accept and which types of files you don’t. For example, you can set your filter to only accept .png, .jpeg., and .jpg file types.

function checkFileType(file, cb) {
    // Allowed ext
    const filetypes = /jpeg|jpg|png/;
    // Check ext
    const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
    // Check mime
    const mimetype = filetypes.test(file.mimetype);

    if (mimetype && extname) {
        return cb(null, true);
    } else {
        cb('Error: Images Only');
    }
}

Set this to the fileFilter property of the upload object:

const upload = multer({
    storage: storage,
    fileFilter: function (req, file, cb) {
        checkFileType(file, cb);
    }
}));