Loopback: Allow remote methods to accept uploaded files

Created on 9 Mar 2017  路  26Comments  路  Source: strongloop/loopback

Allow remote method to accept uploaded file(s) via regular "accepts" parameters.

So far, methods accepting files have to parse them manually from the request object, see loopback-component-storage for an example implementation.

Possible flavours to support:

  • Access the full request as a single "file" (see e.g. https://github.com/strongloop/strong-remoting/issues/318):
    {arg: 'file', type: 'file', http: { source: 'body' }, required: true}

  • Accept multiple files uploaded in a multipart body (see e.g. https://github.com/strongloop/loopback/issues/3264 and https://github.com/strongloop/loopback/issues/3171), this should simplify loopback-component-storage implementation

feature help wanted stale

Most helpful comment

The best way to receive a file is to get the file from the req object by using a file extractor like multiparty and then you have the file to do what ever you want from it. I wrote a little post on how to do that here.

Solved: https://medium.com/@jackscott/upload-files-to-aws-s3-in-loopback-29a3f01119f4

Hope it helps! 馃槃

All 26 comments

Oh , it was marked as "stale"..... We have such requirement + 1

Hi all,
i am using
accepts: {arg: 'file', type: 'File', http: { source: 'body' }, required: true} in my remote method it gives me
error:Swagger: skipping unknown type "File"

can anyone please help me

@Gomathivignesh are you using the latest version of loopback-swagger? Support for file type "accepts" arguments was added by https://github.com/strongloop/loopback-swagger/pull/90, first released in v4.1.0. You will probably need to update your loopback-component-explorer dependency to ^5.0.0 in order to get the latest loopback-swagger version installed in your project.

@bajtos Thanks for your answer,i changed the version of swagger,its works fine and i dint show the unknown type file,but the remote method shows error : Treating unknown remoting type "file" as "any"

my code is
Container.remoteMethod('uploadS3',
{
http: {path: '/uploadS3', verb: 'post'},
accepts: {arg: 'req', type: 'file'},
returns: {arg: 'list', type: 'Object'}
});
Container.uploadS3 = function (req, cb) {
//uploading stuff
cb(err,data);
}

but the remote method shows error : Treating unknown remoting type "file" as "any"

This is expected - strong-remoting does not support input arguments of "file" type. This GitHub issue is tracking the feature request, the issue is still open because the feature has not been implemented yet.

Ok Thanks for reply @bajtos ,is there any way to upload a file to s3 using loopback?i m using loopback-component-storage for s3, i can able to download file from s3, but please see the attachment in that i can't able to upload file in POST API,,can you please provide solution to that..

screenshot from 2017-10-16 17-01-01

Thanks n adv..

@Gomathivignesh I don't think it's possible to upload files from API Explorer now. See https://github.com/strongloop/loopback-example-storage/tree/master/example-3.0 for an example app, look into client directory for the browser code.

Thanks @bajtos above links works for file upload with local,but i need to upload file to s3 so how i configure bucket & folder using loopback,can you please suggest me a solution to that.

hi, I have a question maybe not related to this title but I want to know how to create the data and upload file together to the Loopback, I have done many research still can't find the right way on how to do it. Please suggest the solution if you know how to do it. Thank you.

@JohnHour89 Please see the code snippet for file upload with remote method, this may help you

datasource.json

"amazonS3": {
"name": "amazonS3",
"connector": "loopback-component-storage",
"provider": "amazon",
"key": "xxxxxxxxxxxxxxxxxx",
"keyId": "xxxxxxxxxxxxxxxx",
"maxFileSize": "100000000"//bytes
}

model-config.json

"Container": {
"dataSource": "amazonS3",
"public": true
}

container.json

{
"name": "Container",
"base": "Model",
"properties": {},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}

container.js


let loopBackContext = require('loopback-context');
module.exports = function(Container) {

Container.uploadFile = function(req,res,clientId,agencyId,cb) {
        Container.upload(req,res,{container: '/xxx/yyy'},function(err,data) //container name & file location in s3 
        {
            if(err)console.log(err);
            else{

                cb(err,data);
            }

        })
    };
     Container.remoteMethod('uploadFile',
      {
        accepts: [
            {arg: 'req', type: 'object', 'http': {source: 'req'}},
            {arg: 'res', type: 'object', 'http': {source: 'res'}}

         ],
        http: { path: '/fileUpload', verb: 'Post' },
        returns: { arg: 'data', type: 'Object' }
      });

};

Try in PostMan
API
POST
http://localhost:8080/api/Containers/fileUpload

Request Payload
Formdata - file

@Gomathivignesh this example should upload the file with it metadata only. What I want is like I have attachment field and other data field like this:

{
"attachment": "url of the uploaded image",
"title": "text",
"description" : "description"
}

I want upload the file and can create the other field data together in the Loopback like this.

@JohnHour89 just add the other fields in loopback remote method accepts feilds, in afterremote method of file upload process the data too..

@Gomathivignesh Can you show me the example on how to add the other fields? I still dun understand how to do it

this is mine:

`var CONTAINERS_URL = 'http://localhost:3000/api/containers/';
module.exports = function(File) {

File.upload = function (ctx,options,cb) {
    if(!options) options = {};
    ctx.req.params.container = 'common';
    File.app.models.container.upload(ctx.req,ctx.result,options,function (err,fileObj) {
        if(err) {
            cb(err);
        } else {
            var fileInfo = fileObj.files.file[0];
            File.create({
                name: fileInfo.name,
                type: fileInfo.type,
                container: fileInfo.container,
                url: CONTAINERS_URL+fileInfo.container+'/download/'+fileInfo.name
            },function (err,obj) {
                if (err !== null) {
                    cb(err);
                } else {
                    cb(null, obj);
                }
            });
        }
    });
};

File.remoteMethod(
    'upload',
    {
        description: 'Uploads a file',
        accepts: [
            { arg: 'ctx', type: 'object', http: { source:'context' } },
            { arg: 'options', type: 'object', http:{ source: 'query'} }
        ],
        returns: {
            arg: 'fileObject', type: 'object', root: true
        },
        http: {verb: 'post'}
    }
);

};`

@JohnHour89,You want add some data in API along with file right? Just add in accepts Array,correct me if my understanding is wrong
accepts: [ {arg: 'req', type: 'object', 'http': {source: 'req'}}, {arg: 'res', type: 'object', 'http': {source: 'res'}}, {arg:'xxxx',type: 'Number'}, {arg:'yyyy',type: 'Number'} ]

@Gomathivignesh, hi I was able to achieve like this as shown in the screenshot, I was able to upload the image but always cannot create data in the other model, is it possible to do it? Thank you
screen shot 2017-11-08 at 9 11 26 am

Any updates?

Hello, I am afraid we don't have bandwidth to work on this feature. You are welcome to try to implement and contribute it yourself, but be warned that the implementation is going to be non-trivial.

+1

The best way to receive a file is to get the file from the req object by using a file extractor like multiparty and then you have the file to do what ever you want from it. I wrote a little post on how to do that here.

Solved: https://medium.com/@jackscott/upload-files-to-aws-s3-in-loopback-29a3f01119f4

Hope it helps! 馃槃

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.

Access the full request as a single "file" (see e.g. strongloop/strong-remoting#318):

{arg: 'file', type: 'file', http: { source: 'body' }, required: true}

_Cross-posting my StackOverflow answer https://stackoverflow.com/a/53726432/69868. Please up-vote it if you find it useful._

I am recommending the following solution:

First, configure your server middleware to parser image request bodies:

  1. Install body-parser dependency.

    $ npm install --save body-parser
    
  2. Configure the raw parser by adding the following content to parse section of your server/middleware.json file:

    {
      "body-parser#raw": {
        "limit": "100kb",
        "type": "image/*"
      }
    }
    

    The "limit" option sets the maximum allowed request body size. You don't want to allow arbitrary size to prevent malicious clients from crashing your server on "out of memory" error.

    The "type" option configures content-types that should be parsed by this middleware. In my example above, I am allowing all image types.

Next, implement a remote method accepting the request body. Thanks to the raw body parser, the body stream will be already converted into a Buffer for you. In my example below, I have a simple method that responds with a base64-encoded body.

module.exports = function(Image) {
  Image.analyze = async function(data) {
    // Reject non-image requests, e.g. JSON
    if (!Buffer.isBuffer(data)) {
      const err = new Error('Unsupported media type'); 
      err.statusCode = 415;
      throw err;
    }

    // data is a Buffer containing the request body
    return data.toString('base64');
  };

  Image.remoteMethod('analyze', {
    accepts: [
      // {source: 'body'} is the important part
      {arg: 'data', type: 'object', http: {source: 'body'}},
    ],
    returns: {root: true, type: 'string'},
    http: {path: '/analyze', verb: 'post'},
  });
};

@Gomathivignesh @JohnHour89 Can you share your solution? @bajtos Any updates to get files with multipart/form-data?

I'm using loopback v3.
I am trying to upload an image with json form data. https://github.com/strongloop/loopback-component-storage/issues/237#issuecomment-598296893

Hi @emonddr, thanks for your reply. Are you referring to how to use loopback-component-storage?
I have adapted several solutions to form solution for my problem. I'll post the solution to the above link once I complete my fix.

Was this page helpful?
0 / 5 - 0 ratings