KingFish
KingFish

Reputation: 9173

Blank Data when Uploading Form Using enctype="multipart/form-data"

I have an interesting problem. I'm trying to upload a form by way of

<form enctype="multipart/form-data" action="/myendpoint/:id">
    <input type="hidden" name="data" value="mydata" />
    <input type="file" name="formname" />
</form>

... and my remote method call:

Patient.uploadVideo = function(id, mydata, cb) {
    console.log(mydata);
    return cb(null, { id: 123 });
};


MyModel.remoteMethod(
'uploadVideo',
{
  http: {path: '/:id/recording/:recordingid/videos', verb: 'post'},
  accepts: [
            {arg: 'id', type: 'string', required: true},
            {arg: 'mydata', type: 'object', 'http': {source: 'body'}},
           ]
  }
);

Unfortunately the body is coming in as blank

How do I get the form data? I modified server/datasources.json to include

"storage": {
    "name": "storage",
    "connector": "loopback-component-storage",
    "provider": "filesystem",
    "root": "./server/storage"
}

Still nothing.

Thanks

Upvotes: 3

Views: 843

Answers (2)

Sam Hughes
Sam Hughes

Reputation: 153

Thanks for the guidance. I got file upload working with loopback and angular 2, which considering how small the documentation is for those two is a huge feat. A few expansions:

In MyModel.myFunction = function(req, res, options, cb) {, the options is not strictly necessary. You can just pass any desired options as a "property" of the formData object that one would likely pass into req object. In your example, if options is not passed into the function, but only the formData, then cb will not be assigned and will bork the entire call.

If anyone wants to know how I achieved this, the main calls are:

Angular 2

upload-test.component.ts

let file = event.srcElement.files[0];
let formData:FormData = new FormData();

this.forumPostService.uploadFile(formData).subscribe(
    response => {
        console.log(response);
    }
);

upload-test.service.ts

uploadFile(formData: FormData) {
    //LEAVE HEADERS BLANK. LOOPBACK CALL BORKS IF ASSIGNED!
    let headers = new Headers();
    return this.http
        .post('http://apiUrl/myModel/uploadTest',
            formData,
            {headers: headers})
        .map((response: Response) => {
            return response.json();
        });
}

"formData", which holds the file, is passed into "req" in http request to loopback API

Loopback

uploadTest.js

myModel.uploadTest = function(req, res, callback) {
    var storage = require('loopback-component-storage');
    //"root:'/'" will point to home drive, e.g. 'C://'
    var storageService = storage.StorageService({provider:'filesystem', root:'/'});
    /*"upload" will give e.g. 'C://upload', make sure this folder exists, 
    it wont create it for you*/
    storageService.upload(req, res, { container: 'upload'}, function(err, data) {
        if (err) {
            callback(err);
        }
        else {
            console.log(data.files.file[0]);
            callback(null, data.files.file[0]);
        }
    });
}

PostSections.remoteMethod(
    'uploadTest',{
        accepts: [
            {arg: 'req', type: 'object', 'http': {source: 'req'}},
            {arg: 'res', type: 'object', 'http': {source: 'res'}}
        ],
        returns: [
            { arg: 'Result', type: 'object' }
        ],
        http: { path: '/uploadTest', verb: 'post'}
    }
);

Upvotes: 0

KingFish
KingFish

Reputation: 9173

So unfortunately the documentation is very limited when discussing how to upload files. There is one reference to the module "loopback-component-storage", one has to tear into it in order to find this diamond in the rough.

var storage     =   require('loopback-component-storage');

MyModel.myFunction = function(req, res, options, cb) {
    var storage     =   require('loopback-component-storage');
    var storageService  = storage.StorageService({provider: 'filesystem', root: '/tmp'});

    storageService.upload(req, res, { container: 'upload' }, function(err, data) {
        console.log(data); // this provides a nice object with all of the variables and data wrt the file that was uploaded
        /// ..etc
    });
 };
 MyModel.remoteMethod(
    'myFunction',
    {
        http: {path: '/mypath', verb: 'post'},
        accepts: [
          {arg: 'req', type: 'object', 'http': {source: 'req'}},
          {arg: 'res', type: 'object', 'http': {source: 'res'}}
        ],
        returns: {arg: 'something', type: 'object'}
    }
);

You can find the documentation for StorageService here

Upvotes: 5

Related Questions