3

I created a simple file uploading application with loopbackjs. In the application's client side I used simple HTML and Javascript code, calling a loopback api with an AJAX call:

$('#upload-input').on('change', function () {

    var files = $(this).get(0).files;

    if (files.length > 0) {
        // One or more files selected, process the file upload
        var form = new FormData();

        for (var index = 0; index < files.length; index++) {

            var file = files[index];
            form.append('Uploded Files', file, file.name);
        }

        $.ajax({
            url: 'api/fileupload/upload',
            type: 'POST',
            data: form,
            processData: false,
            contentType: false,
            success: function (data) {
                console.log('upload successful!');
            }
        });
    }

});

We are not getting files on the server side. On the server side we created a Loopback API, but how can we upload files with this API?

This is my loopback API code:

FileUpload.remoteMethod

(
        'upload', {
            http: {
                verb: 'post',
            },
            accepts:
            [
                { arg: 'ctx', type: 'object', http: { source: 'context' } },
                { arg: 'options', type: 'object', http: { source: 'query' } }

            ],
            returns: {
                arg: 'data',
                type: 'string',
                root: true
            }
        }
    );

    FileUpload.upload = function (context, options, callback) {
        //context.req.params = 'common';

    };
CPHPython
  • 12,379
  • 5
  • 59
  • 71
Rakesh
  • 53
  • 1
  • 1
  • 8
  • did u check loopback-storage-component - http://loopback.io/doc/en/lb3/Storage-component.html – Aks1357 Apr 14 '17 at 10:28
  • Yes , But how can we used it !! please clarify – Rakesh Apr 14 '17 at 10:30
  • Thanks , we need to store files on Server side not in Container . – Rakesh Apr 14 '17 at 10:32
  • check the link, it has steps to implement it, also link to example - https://github.com/strongloop/loopback-example-storage – Aks1357 Apr 14 '17 at 10:33
  • 1
    Conatiners are nothing but folders on server side, will give another option as answer as it won't fit in comment box – Aks1357 Apr 14 '17 at 10:34
  • thanks Again , Actually Our Problem is that , we need to upload a File from Client Side and Store this File in Database , But Before save in DB , we need to get files on Server side , if we get Files on Server side via Post API than we can easily store file in DB . – Rakesh Apr 14 '17 at 10:38
  • on Server Side We are using Loopback APIs , So we are not able to get the uploaded file Properties . – Rakesh Apr 14 '17 at 10:45

4 Answers4

8

Install multer : https://github.com/expressjs/multer

npm install --save multer

In MyModel.js

var multer = require('multer');
var fs = require('fs');

module.exports = function (MyModel) {
    var uploadedFileName = '';
    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
            // checking and creating uploads folder where files will be uploaded
            var dirPath = 'client/uploads/'
            if (!fs.existsSync(dirPath)) {
                var dir = fs.mkdirSync(dirPath);
            }
            cb(null, dirPath + '/');
        },
        filename: function (req, file, cb) {
            // file will be accessible in `file` variable
            var ext = file.originalname.substring(file.originalname.lastIndexOf("."));
            var fileName = Date.now() + ext;
            uploadedFileName = fileName;
            cb(null, fileName);
        }
    });


    MyModel.upload = function (req, res, cb) {
        var upload = multer({
            storage: storage
        }).array('file', 12);
        upload(req, res, function (err) {
            if (err) {
                // An error occurred when uploading
                res.json(err);
            } else {
                res.json(uploadedFileName);
            }
        });        
    };

    MyModel.remoteMethod('upload',   {
        accepts: [{
            arg: 'req',
            type: 'object',
            http: {
                source: 'req'
            }
        }, {
            arg: 'res',
            type: 'object',
            http: {
                source: 'res'
            }
        }],
        returns: {
             arg: 'result',
             type: 'string'
        }
    });
};

Frontend - I use AngularJS, so for that follow -https://github.com/nervgh/angular-file-upload

there are also other such directives to use

P.S. - As per your comment - Actually Our Problem is that , we need to upload a File from Client Side and Store this File in Database , But Before save in DB , we need to get files on Server side , if we get Files on Server side via Post API than we can easily store file in DB

Can't provide you exact solution, but using above method files will be uploaded in your /client/uploads folder, once uploaded then you have control on what to do with file and once everything is done, eventually delete it(optional)

sarkiroka
  • 1,485
  • 20
  • 28
Aks1357
  • 1,062
  • 1
  • 9
  • 19
  • Unhandled error for request POST /api/fileupload/upload: Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11) – Rakesh Apr 14 '17 at 12:06
  • I think its generate error here- res.json(uploadedFileName); – Rakesh Apr 14 '17 at 12:11
  • can you console `file` variable near, // file will be accessible in `file` variable and check if you get anything there – Aks1357 Apr 14 '17 at 12:13
  • Control is not going there , so its Print nothing , I am putting my code please check if something missing . – Rakesh Apr 14 '17 at 12:18
  • @Aks1357 its working fine. but res.end(result) not showing any data. – Santhosh Feb 19 '19 at 13:47
  • @Santhosh - cannot provide a proper solution until I see your modified code. Try replicating to the above code. Debug with multiple `console.log` as by which point you getting the value, and where it's getting empty. – Aks1357 Feb 19 '19 at 14:01
  • @Aks1357 i am debugging to get the res.end(result) as expected value. but postman response showing only 204 No Content. – Santhosh Feb 21 '19 at 05:54
  • @Aks1357 It's my modified code: https://github.com/santhosharuchamy/loopback-file-upload/blob/90a7ac8ececa7a73b38aad5b6715aba26a260599/Loopback%20custom%20fileupload.js#L80 – Santhosh Feb 21 '19 at 06:08
  • @Santhosh, try to debug by `console.log(result)` before fs.unlink, if the result is getting printed. Or try using res.send() or res.json() instead res.end() – Jayesh_naik Feb 21 '19 at 10:18
  • @Jayesh_naik console.log(result) print the value before fs.unlink i am checking but not return any response in postman only showing the 204 No Content.. – Santhosh Feb 23 '19 at 10:18
  • i am tried these res.send() or res.json() or res.end() but not working – Santhosh Feb 23 '19 at 10:28
  • @Jayesh_naik i am tried these res.send() or res.json() or res.end() but not working – Santhosh Feb 27 '19 at 12:53
1

Please check this code:

module.exports = function (FileUpload) {
var multer = require('multer');

    FileUpload.remoteMethod(
        'upload', {
            http: {
                verb: 'post',
            },
            accepts:
            [{
                arg: 'req',
                type: 'object',
                http: {
                    source: 'req'
                }
            }, {
                arg: 'res',
                type: 'object',
                http: {
                    source: 'res'
                }
            }],
            returns: {
                arg: 'data',
                type: 'string',
                root: true
            }
        }
    );

    var uploadedFileName = '';

    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
            // checking and creating uploads folder where files will be uploaded
            var dirPath = 'client/uploads/'
            if (!fs.existsSync(dirPath)) {
                var dir = fs.mkdirSync(dirPath);
            }
            cb(null, dirPath + '/');
        },
        filename: function (req, file, cb) {
            // file will be accessible in `file` variable
            console.log("----------Second Rakesh---");
            console.log(file);
            var ext = file.originalname.substring(file.originalname.lastIndexOf("."));
            var fileName = Date.now() + ext;
            uploadedFileName = fileName;
            cb(null, fileName);
        }
    });

    FileUpload.upload = function (req, res, callback) {

        var upload = multer({
            storage: storage
        }).array('file', 12);

        upload(req, res, function (err) {
            if (err) {
                // An error occurred when uploading
                res.json(err);
            }
            console.log("-------------Rakesh"); // Its Printing Rakesh

            res.json(uploadedFileName);
        });
    };
};
Muhammad Noman
  • 1,344
  • 1
  • 14
  • 28
Rakesh
  • 53
  • 1
  • 1
  • 8
  • control is not printing - console.log("----------Second Rakesh---"); – Rakesh Apr 14 '17 at 12:32
  • Add `var fs = require('fs');` after `multer` as we are using that also, so it was not declared in the code but was used, which generated error – Aks1357 Apr 14 '17 at 13:58
  • Thank you very much , do you see my code ? You mean , after var multer = require('multer'); we need to add var fs = require('fs'); – Rakesh Apr 17 '17 at 05:27
  • Thanks , But it showing Error - Unhandled error for request POST /api/fileupload/upload: Error: Can't set headers after they are sent. and it also not Printing Console.log(file). – Rakesh Apr 17 '17 at 06:13
  • When I print 'storage' in console it show me - DiskStorage { getFilename: [Function: filename], getDestination: [Function: destination] } – Rakesh Apr 17 '17 at 06:20
  • control not printing 'file' object near '// file will be accessible in `file` variable' in console !! Please check my code . – Rakesh Apr 17 '17 at 06:24
  • I replaced res.json(err); with res.end("File is uploaded"); After Changing Error - Unhandled error for request POST /api/fileupload/upload: Error: Can't set headers after they are sent. Solved . But file not uploading !!!!!!! – Rakesh Apr 17 '17 at 06:37
  • changing that, doesn't matter much, console `err` and change `if` to `if else` – Aks1357 Apr 18 '17 at 10:57
  • Thanks , now its Working. can you tell me about Authentication and Security to Loopback API . How can i implement it in my Project. – Rakesh Apr 18 '17 at 11:23
  • sure, what are you using, angularJS..? links to get started - http://loopback.io/doc/en/lb3/Authentication-authorization-and-permissions.html , http://loopback.io/doc/en/lb3/Create-AngularJS-client.html – Aks1357 Apr 18 '17 at 12:05
  • Actually , For now i am not using AngularJs , I need to do in loopback. can we do only with loopback and NodeJS . – Rakesh Apr 19 '17 at 06:16
  • can you guide me for Authentication-authorization to loopback apis. – Rakesh Apr 19 '17 at 06:36
  • i go through http://loopback.io/doc/en/lb3/Authentication-authorization-and-permissions.html#preparing-access-control-models but i can not get that where i need to start. please tell me what i need to do !!!! – Rakesh Apr 19 '17 at 09:42
  • it's a very topic which cannot be covered here, you are on the right link, please follow steps the have mentioned like creating this file `server/boot/authentication.js` and `copy pasting` the code they have given, just follow the steps mentioned in the documentation – Aks1357 Apr 19 '17 at 09:58
  • can you give me source code for Reference !! if possible – Rakesh Apr 19 '17 at 10:04
  • can you tell me "AccessToken": { "dataSource": "db", "public": false, "relations": { "user": { "type": "belongsTo", "model": "user", "foreignKey": "userId" } } here what is userid??? – Rakesh Apr 19 '17 at 10:17
  • check this example, source code is also provided - https://github.com/strongloop/loopback-example-access-control – Aks1357 Apr 19 '17 at 10:32
  • I am following this link https://strongloop.com/strongblog/working-with-loopback-authentication-and-authorization/ and create same Project , but i am getting this error- TypeError: Cannot convert undefined or null to object . – Rakesh Apr 19 '17 at 13:13
  • This is Git url- https://github.com/cfjedimaster/StrongLoopDemos/blob/master/simpleauthdemo/server/boot/authentication.js – Rakesh Apr 19 '17 at 13:14
  • This is error-POST /api/appusers/login: TypeError: Cannot convert undefined or null to object – Rakesh Apr 19 '17 at 13:18
  • Please check this Question - http://stackoverflow.com/questions/43513313/how-to-add-authentication-to-loopback-custom-api – Rakesh Apr 20 '17 at 08:32
0

You can upload files/Images using loopback's default storage component. Go to the doc link and follow the instruction and specially look how the example project implemented the file uploading.

You will have to create a datasource and a container model for this purpose.

Create Datasource:

$ lb datasource
[?] Enter the data-source name: myfilesystem
[?] Select the connector for myfilesystem: other
[?] Enter the connector name: loopback-component-storage
[?] Install storage (Y/n)

create the container model:

  • Model name: Container
  • Data source: myfilesystem
  • Base class: Model
  • Expose Reviewer via the REST API? Yes
  • Custom plural form (used to build REST URL): Yes
asmmahmud
  • 4,844
  • 2
  • 40
  • 47
0

This worked for me using LoopbackJs

Loopback framework is based on ExpressJs by the way

You can consider this answer as and adapted version of https://github.com/blueimp/jQuery-File-Upload/ for LoopbackJs

Install plugin dependecy:

npm install jquery-file-upload-middleware

Add this snippet to your /server/server.js :

 //Load Jquery File Upload handler
      var upload = require('jquery-file-upload-middleware'),
        bodyParser = require('body-parser');

        // configure upload middleware
        upload.configure({
            uploadDir: __dirname + '/public/uploads',
            uploadUrl: '/uploads',
            imageVersions: {
                thumbnail: {
                    width: 80,
                    height: 80
                }
            }
        });



        app.use('/upload', upload.fileHandler());
        app.use(bodyParser.raw({ type: 'application/vnd.custom-type' }))

Modify middleware.js with the following snippet so your app can serve static HTML resources in /client folder (this file belongs LoopbackJs framework BTW):

...
    "files": {
  "loopback#static": {
    "params": "$!../client" 
  }
}
...

Download and place in /client/test file-upload webpage : File Upload Webpage

Run your node.app and point to http://localhost:3000/files/ You should be able to upload files and found the uploaded filename response in the Network tab:

enter image description here

julianm
  • 2,393
  • 1
  • 23
  • 24