Upload on AWS S3 with Express.js and Vue.js - Part 1

Posted on December 1, 2019 in
3 min read

I'm refactoring my favorite side project.

Part of this relies on how the file-upload works both on the backend and frontend as well.

In PRESENTA the external files are uploaded using AWS S3 service. The real upload happens straight from the front-end app to the AWS servers. The backend is in charge only to request the one-time token from AWS. Here the flow:

  • The frontend asks to the backend a valid token (this way the backend can make some additional validation about auth and other stuff)
  • The backend asks to AWS the same and routes it to the frontend
  • The frontend begins a PUT request to AWS server to upload the files
  • The dialogue during the upload happens only between the frontend and the S3 service

The backend

In this tutorial, I'm explaining the backend code that is an Express.js based app. The dependencies (that need to be installed) are:

  • express
  • cors
  • dotenv
  • aws-sdk

Here the minimal Express app:

const express = require('express')
const path = require('path')
const app = express()
const port = process.env.PORT || 3131

app.listen(port, () => console.log('Server is running on port: ' + port))

Set-up the CORS

We need a nice dialogue between the backend and the frontend, therefore, we enable the CORS communication with:

const cors = require('cors')
var origins = {
  origin: ['http://localhost:8080'],
  optionsSuccessStatus: 200,
  credentials: false
}
app.use(cors(origins))

Auth with AWS

Here the authentication with S3 using your personal credentials:

const aws = require('aws-sdk')
aws.config.region = 'eu-west-3'
const S3_BUCKET = process.env.S3_BUCKET_NAME

The route

In this little webserver contains only one route with comments between the lines

app.get('/s3', (req, res) => {
  
  // get the params from the initial request
  const fileName = req.query.filename
  const fileType = req.query.filetype
  const ext = path.extname(fileName)
    
  // define the location and the file name
  const pathName = path.join('myfoldertest', 'myuploadedfile' + ext)

  const s3 = new aws.S3()
    
  // configure the S3 object to get the token
  const s3Params = {
    Bucket: S3_BUCKET,
    Key: pathName,
    Expires: 60 * 15,
    ContentType: fileType,
    ACL: 'public-read'
  }
    
  // ask for the token
  s3.getSignedUrl('putObject', s3Params, (err, data) => {
    if (err) {
      return res.status(500).json(err)
    }

    const returnData = {
      signedRequest: data,
      url: `${pathName}`
    }
        
    // returning the token to the frontend
    res.status(200).json(returnData)
  })
})

This little server can be run with node index.js and it will listen at http://localhost:3131/s3 with the filename and the filetype parameters correctly set.

This is a bare-bone example without many error handling, just to demonstrate this particular functionality. Full source code here.

In part 2 I'll dive in the frontend part, of course.

Stay tuned.