Zahirul Haque
Zahirul Haque

Reputation: 1649

How to upload file to s3 through nodejs express from Angularjs

I am facing problem to upload file to s3 by nodejs express, and angularjs.

I am using angular directive to send file to node express and from node to s3.

Angular directive :

 (function() {
  'use strict';
  angular.module('app').directive('ngFileModel', ['$parse', function ($parse) {
      return {
          restrict: 'A',
          link: function (scope, element, attrs) {
              var model = $parse(attrs.ngFileModel);
              var isMultiple = attrs.multiple;
              var modelSetter = model.assign;
              element.bind('change', function () {
                  var values = [];
                  angular.forEach(element[0].files, function (item) {
                      var value = {
                         // File Name 
                          name: item.name,
                          //File Size 
                          size: item.size,
                          //File URL to view 
                          url: URL.createObjectURL(item),
                          // File Input Value 
                          _file: item
                      };
                      values.push(value);
                  });
                  scope.$apply(function () {
                      if (isMultiple) {
                          modelSetter(scope, values);
                      } else {
                          modelSetter(scope, values[0]);
                      }
                  });
              });
          }
      };
  }]);


})();

Html code

<input type="file" id="upme" ng-file-model="files" multiple style="display:none;" />
         <div ng-if="files.length>0" ng-init="vm.uploadFile()"></div>

Server side:

exports.upload = function(req, res){
  var images = req.body.images;

    //res.send(images);
   // console.dir(images)

   images.forEach(function(file){


   // console.dir(file);
    S3.upFile('testbucket',file.name, file.url, function(err, data){

      if(err){
        console.log(err)
      }else{
        console.dir(data);
      }

    });

   });

Problem, The upload function works and I get something has been uploaded on s3 bucket, the file name appears in bucket; but it seems that is not actual size of the file and I can not open. when I click on the file url it say to download the file, after I download the file, it does not open. I think there may have any problem to parse the file in the node server before uploadin to s3. But I can't identify which solution should be there.

I also get one error in the console.

TypeError: path must be a string or Buffer
    at TypeError (native)
    at Object.fs.open (fs.js:625:11)
    at ReadStream.open (fs.js:1708:6)
    at new ReadStream (fs.js:1695:10)
    at Object.fs.createReadStream (fs.js:1643:10)

I have made s3 file upload function as module in separate file. Here is module function of file upload

// uploading file or object into bucket
exports.upFile = function(bucket_name, key, file, next){

  var params = {Bucket: bucket_name, Key: key, Body: fs.createReadStream(file), ACL:"public-read"};
  s3.upload(params, function(err, data) {
    next(err, data);
  });

};

I appreciate any help from experts.

Upvotes: 0

Views: 1563

Answers (1)

Muhammad Naeem
Muhammad Naeem

Reputation: 121

You are not giving a file as an argument to the upload function but an object URL. To correct your implementation, you have to make some changes in angular. Firstly, you should send files as multipart form data from angular. You can achieve this by using:

var form = new formData();
angular.forEach(element[0].files, function (item) {
    form.append('file', item);
});

Send this form data to your node server using http request. You can define the route and http method using express in nodejs. On angularJS the request should look something like this:

$http.post('/test_route', form, {
   withCredentials: false,
   headers: {
       'Content-Type': undefined
   },
   trnasformRequest: angular.identity
}).success(function(data) {
    // do something with data from server
});

At node server, when you receive the request you have to extract files from form data. First define a route and method using express:

var multiparty = require('multiparty');

app.post('test_route', function(req, res) {
    var form = new multiparty.Form();
    form.parse(req, function(err, fields, files) {
        var files_to_uplaod = files.file;
        files_to_upload.forEach(function(file) {
            read_file = fs.readFileSync(file.path);
            var params = {Bucket: bucket_name, Key: file.originalFilename, Body: read_file, ACL:"public-read"};
            s3.upload(params, function(err, data) {
                next(err, data);
                // once the file is uploaded you can remove the file from local disk which is saved whn multipart data arrives.
                fs.unlink(file.path, function(err) {
                    if (err) {console.log(err);}
                });   
            });
        });
    }
});

To parse the multiform on node server, use the multiparty module. More information can be found here: https://www.npmjs.com/package/multiparty

Upvotes: 1

Related Questions