title: ExpressJS Uploading and Display Image from AWS S3
body: <p>I have been following the Heroku "<a href="https://devcenter.heroku.com/articles/s3-upload-node" rel="nofollow">Direct to S3 File Uploads in Node.js</a>" to be able to upload and display images from my AWS S3 bucket. I made the CORS configuration for the bucket I am using in this project, but I am not seeing any images uploaded to my bucket and am not able to display any images. When I try to console.log my onError method for the file upload, I get <code>undefined</code>. I do not run into any errors when I <code>POST</code>. Provided below is my code:</p>
  
  <p>eventsModel.js:</p>
  
  <pre><code>var mongoose = require('mongoose');
  var Schema = mongoose.Schema;
  
  var EventSchema = new Schema({
      name: String,
      title: String,
      company: String,
      url: String,
      date: { type: Date, default: Date.now },
      speakerImage: String
  
  });
  
  module.exports = mongoose.model('Event', EventSchema);
  </code></pre>
  
  <p>routes.js:</p>
  
  <pre><code>var express = require('express');
  var router = express.Router();
  var Event = require('./models/eventsModel');
  
  router.get('/sign_s3', function(req, res){
      aws.config.update({accessKeyId: "My Access Key", secretAccessKey: "My Secret Key"});
      var s3 = new aws.S3();
      var s3_params = {
          Bucket: "My Bucket Name",
          Key: req.query.s3_object_name,
          Expires: 60,
          ContentType: req.query.s3_object_type,
          ACL: 'public-read'
      };
      s3.getSignedUrl('putObject', s3_params, function(err, data){
          if(err){
              console.log(err);
          }
          else{
              var return_data = {
                  signed_request: data,
                  url: 'https://'+"My Bucket Name"+'.s3.amazonaws.com/'+req.query.s3_object_name
              };
              res.write(JSON.stringify(return_data));
              res.end();
          }
      });
  });
  
  router.route('/admin/events/create')
  
      .post(function(req, res){
  
          var events = new Event();
  
          events.name = req.body.name;
          events.title = req.body.title;
          events.company = req.body.company;
          events.url = req.body.url;
          events.speakerImage = req.body.speakerImage;
  
          events.save(function(err){
              if (err)
                  res.send(err);
  
              res.redirect(303, '/events');
  
          });
      })
  
      .get(function(req, res){
          Event.find(function(err, events){
              if (err)
                  res.send(err);
  
              res.render('pages/events-create.ejs');
          });
      });
  
  
  
  router.route('/admin/events/:events_id')
  
      .get(function(req, res){
          Event.findById(req.params.events_id, function(err, events){
              if (err)
                  res.send(err);
  
              res.json(events);
          });
      })
  
      .put(function(req, res){
  
          Event.findById(req.params.events_id, function(err, events){
              if (err)
                  res.send(err);
  
              res.json({ message: 'Event Updated'});
          });
      });
  
  //GET '/events'
  router.get('/events', function(req, res) {
      Event.find({})
          .sort({'date': -1})
          .exec(function(err, events) {
          if (err)
              res.send(err);
  
          console.log(events.speakerImage);
          console.log(events.name);
  
          res.render('pages/events.ejs', {
              events : events
          });
      });
  });
  </code></pre>
  
  <p>events-create.ejs:</p>
  
  <pre><code>&lt;!DOCTYPE HTML&gt;
  &lt;html&gt;
  &lt;head&gt;
      &lt;% include ../partials/head %&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
      &lt;% include ../partials/navigation %&gt;
  
  &lt;div class="grid" id="create-event-container"&gt;
          &lt;div class="col-1-1"&gt;
              &lt;div id="create-event"&gt;
                  &lt;h1&gt;&lt;i&gt;Create Event&lt;/i&gt;&lt;/h1&gt;
                  &lt;input type="file" id="files"/&gt;
                  &lt;p id="status"&gt;Please select a file&lt;/p&gt;
                  &lt;div id="preview"&gt;&lt;img src="/images/event-placeholder.png"&gt;&lt;/div&gt;
                  &lt;form action="/admin/events/create" method="POST"&gt;
                      &lt;input type="hidden" id="speaker-image" name="speakerImage" value="public/images/event-placeholder.png" /&gt;
                      Name: &lt;input type="text" name="name"&gt;&lt;br&gt;
                      Title: &lt;input type="text" name="title"&gt;&lt;br&gt;
                      Company: &lt;input type="text" name="company"&gt;&lt;br&gt;
                      Website: &lt;input type="text" name="url"&gt;&lt;br&gt;
                      Upcoming Event?: &lt;input type="checkbox" name="upcomingEvent"&gt;&lt;br&gt;
                      &lt;input type="submit" value="Submit"&gt;&lt;br&gt;
                  &lt;/form&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;script type="text/javascript" src="/js/s3upload.js"&gt;
  
      &lt;script&gt;
      function s3_upload(){
          var status_elem = document.getElementById("status");
          var url_elem = document.getElementById("speaker-image");
          var preview_elem = document.getElementById("preview");
          var s3upload = new S3Upload({
              file_dom_selector: 'files',
              s3_sign_put_url: '/sign_s3',
              onProgress: function(percent, message) {
                  status_elem.innerHTML = 'Upload progress: ' + percent + '% ' + message;
              },
              onFinishS3Put: function(public_url) {
                  status_elem.innerHTML = 'Upload completed. Uploaded to: '+ public_url;
                  url_elem.value = public_url;
                  preview_elem.innerHTML = '&lt;img src="'+public_url+'" style="width:300px;" /&gt;';
              },
              onError: function(status) {
                  status_elem.innerHTML = 'Upload error: ' + status;
                  console.log(status_elem.innerHTML);
              }
          });
      }
      /*
      * Listen for file selection:
      */
      (function() {
          var input_element = document.getElementById("files");
          input_element.onchange = s3_upload;
      })();
      &lt;/script&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>server.js:</p>
  
  <pre><code>//Load Express
  var express = require('express');
  var app = express();
  var bodyParser = require('body-parser');
  var mongoose = require('mongoose');
  var eventsDb = require('./config/eventsDb');
  var http = require('http');
  var path = require('path');
  var aws = require('aws-sdk');
  
  app.use(bodyParser.urlencoded({ extended: true})); //get data from a POST method
  app.use(bodyParser.json());
  
  mongoose.connect(eventsDb.url);
  
  var port = process.env.PORT || 8080; //set port
  
  app.set('view engine', 'ejs'); //set EJS template engine
  
  app.use(express.static(__dirname + '/public')); // set the public directory
  
  var AWS_ACCESS_KEY = process.env.AWS_ACCESS_KEY;
  var AWS_SECRET_KEY = process.env.AWS_SECRET_KEY;
  var S3_BUCKET = process.env.S3_BUCKET
  
  var Event = require('./app/models/eventsModel');
  
  
  var routes = require('./app/routes');
  app.use(routes);
  
  app.listen(port);
  console.log('access at port:' + port);
  </code></pre>
  
  <p>s3upload.js (Also can be accessed in the repo from the blog article):</p>
  
  <pre><code>(function() {
  
    window.S3Upload = (function() {
  
      S3Upload.prototype.s3_object_name = 'default_name';
  
      S3Upload.prototype.s3_sign_put_url = '/signS3put';
  
      S3Upload.prototype.file_dom_selector = 'file_upload';
  
      S3Upload.prototype.onFinishS3Put = function(public_url) {
        return console.log('base.onFinishS3Put()', public_url);
      };
  
      S3Upload.prototype.onProgress = function(percent, status) {
        return console.log('base.onProgress()', percent, status);
      };
  
      S3Upload.prototype.onError = function(status) {
        return console.log('base.onError()', status);
      };
  
      function S3Upload(options) {
        if (options == null) options = {};
        for (option in options) {
          this[option] = options[option];
        }
        this.handleFileSelect(document.getElementById(this.file_dom_selector));
      }
  
      S3Upload.prototype.handleFileSelect = function(file_element) {
        var f, files, output, _i, _len, _results;
        this.onProgress(0, 'Upload started.');
        files = file_element.files;
        output = [];
        _results = [];
        for (_i = 0, _len = files.length; _i &lt; _len; _i++) {
          f = files[_i];
          _results.push(this.uploadFile(f));
        }
        return _results;
      };
  
      S3Upload.prototype.createCORSRequest = function(method, url) {
        var xhr;
        xhr = new XMLHttpRequest();
        if (xhr.withCredentials != null) {
          xhr.open(method, url, true);
        } else if (typeof XDomainRequest !== "undefined") {
          xhr = new XDomainRequest();
          xhr.open(method, url);
        } else {
          xhr = null;
        }
        return xhr;
      };
  
      S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
        var this_s3upload, xhr;
        this_s3upload = this;
        xhr = new XMLHttpRequest();
        xhr.open('GET', this.s3_sign_put_url + '?s3_object_type=' + file.type + '&amp;s3_object_name=' + this.s3_object_name, true);
        xhr.overrideMimeType('text/plain; charset=x-user-defined');
        xhr.onreadystatechange = function(e) {
          var result;
          if (this.readyState === 4 &amp;&amp; this.status === 200) {
            try {
              result = JSON.parse(this.responseText);
            } catch (error) {
              this_s3upload.onError('Signing server returned some ugly/empty JSON: "' + this.responseText + '"');
              return false;
            }
            return callback(result.signed_request, result.url);
          } else if (this.readyState === 4 &amp;&amp; this.status !== 200) {
            return this_s3upload.onError('Could not contact request signing server. Status = ' + this.status);
          }
        };
        return xhr.send();
      };
  
      S3Upload.prototype.uploadToS3 = function(file, url, public_url) {
        var this_s3upload, xhr;
        this_s3upload = this;
        xhr = this.createCORSRequest('PUT', url);
        if (!xhr) {
          this.onError('CORS not supported');
        } else {
          xhr.onload = function() {
            if (xhr.status === 200) {
              this_s3upload.onProgress(100, 'Upload completed.');
              return this_s3upload.onFinishS3Put(public_url);
            } else {
              return this_s3upload.onError('Upload error: ' + xhr.status);
            }
          };
          xhr.onerror = function() {
            return this_s3upload.onError('XHR error.');
          };
          xhr.upload.onprogress = function(e) {
            var percentLoaded;
            if (e.lengthComputable) {
              percentLoaded = Math.round((e.loaded / e.total) * 100);
              return this_s3upload.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
            }
          };
        }
        xhr.setRequestHeader('Content-Type', file.type);
        xhr.setRequestHeader('x-amz-acl', 'public-read');
        return xhr.send(file);
      };
  
      S3Upload.prototype.uploadFile = function(file) {
        var this_s3upload;
        this_s3upload = this;
        return this.executeOnSignedUrl(file, function(signedURL, publicURL) {
          return this_s3upload.uploadToS3(file, signedURL, publicURL);
        });
      };
  
      return S3Upload;
  
    })();
  
  }).call(this);
  </code></pre>