3

I've tried everything recommended in How can I use body-parser with LoopBack? and yet still no luck.

My client app is in AngularJS and uses the ng-file-upload module, specifically like this:

      Upload.upload({
        url: apiUrl + '/Recipes/uploadImage',
        file: $scope.picFile,
        params: {
          recipeId: newRecipe.id
        }
      })
      .then(function(res) {
        console.log('succes:', res);
      }, function(err) {
        console.log('error:', err);
      }, function(evt) {
        console.log('progress:', evt);
      });

On the server (Loopback) side, I have made sure that server/middleware.json has the middleware registered:

  ...
  "parse": {
    "body-parser#json": {},
    "body-parser#urlencoded": {"params": { "extended": true }}    
  },
  ...

For good measure, although I'm not sure if body-parser is even needed in addition to multer (and body-parser is being required anyway because of being registered in middleware.json), I've included these lines in server/server.js:

var bodyParser = require('body-parser');
var multer = require('multer');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(multer().any()); // for parsing multipart/form-data

And I've also installed both:

npm install --save multer
npm install --save body-parser

Finally, my custom remote method looks like this:

  Recipe.remoteMethod(
    'uploadImage',
    {
      accepts: [
                { arg: 'req', type: 'object', http: { source: 'req' }               },
                { arg: 'res', type: 'object', http: { source: 'res' } }
            ],
      returns: {
        arg: 'status', type: 'object', root: true
      },
      http: {verb: 'post'}
    }
  );

The actual function so far is just trying to get something to work with:

Recipe.uploadImage = function (req, query, cb) {

        console.log('params:', req.file, req.recipeId);
        console.log('body:', req.body);
        ... // And once I can get this I'm going to get the stream and pipe it to a remote storage container, but I need the file first!

The output from posted to the above is

params: undefined undefined
body: {}

Which sort of suggests that multer isn't really doing its thing, and I'm not really getting the parts of the multi-part form post?

Help!

Community
  • 1
  • 1
Anselan
  • 396
  • 3
  • 13
  • UPDATE: I managed to get things working more easily using `formidable`, but would be curious to know how to get the `multer` working properly as a middleware in Loopback. – Anselan May 06 '16 at 10:30
  • You can get file uploads in loopback without having to add middleware by using a Storage component. Check out https://docs.strongloop.com/display/public/LB/Storage+component if you haven't already. We're using it in concert with ng-file-upload and Amazon S3. – notbrain May 06 '16 at 18:50
  • But how would that help if you wanted to transform the file stream before piping it off to the storage? – Anselan Jul 26 '16 at 14:16
  • It probably wouldn't, but if you just get the file on the server first with a quick setup of a built-in feature, might help. Then you've got the file on the server and you can do whatever you need transform-wise. Plus you have a backup of the original. But I have no idea about your real requirements or why you're transforming the stream, so it might not make sense. – notbrain Jul 27 '16 at 22:50

1 Answers1

0

Tell me if that help you. With upload and check information in loopback3.

/server/server.js

var loopback = require('loopback');
var bodyParser = require('body-parser');
var multer = require('multer');
var boot = require('loopback-boot');

var app = module.exports = loopback();


app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(multer().any()); // for parsing multipart/form-data



app.start = function() {

/server/midleware.json

  "parse": {
    "body-parser#json": {},
    "body-parser#urlencoded": {"params": { "extended": true }}
  },

final model:

module.exports = function(Offer) {

    Offer.add = function (ctx,options,cb) {
    console.log(ctx.req.body);
    console.log(ctx.req.files[0]); 
    if(!options) options = {};
    ctx.req.params.container = 'x';
Container.upload(ctx.req,ctx.result,{container: 'x'},function (err,fileObj) {

fileObj.files[''] ...

and remote my is different then your

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

I use postman to send data explorer do not allow for files. Something explorer do some error.

with this options: address: http://0.0.0.0:3000/api/Offers/add?access_token=c6qlcG19lhEYp6C6CztcPHYKpXj2uA3qARMJU7nxBL3trjveHbxNTo0BsvV3vleO

type: POST

authentication: no authentication

headers: empty (default content type is included)

body: form-data with data you want to send

How to configure storage connector to filter size and type of file loopback:

      "storage": {
    "name": "storage",
    "nameConflict": "makeUnique",
    "connector": "loopback-component-storage",
    "provider": "filesystem",
    "root": "./server/storage",
    "maxFileSize": "5242880",
    "allowedContentTypes":["image/gif", "image/png", "image/tiff", "image/webp", "image/x-icon", "image/jpeg", "image/svg+xml", "image/x-icon"]
  }

How to create relation for model and file in loopback? How to save file info in loopback? You need to have model in data base what save name of file.

        Container.upload(ctx.req,ctx.result,{container: 'x'},function (err,fileObj) {
cFile  =  fileObj.files[''][0];
    Image.create({
                 name: cFile.name,
                 type: cFile.type,
                 originalFilename: cFile.originalFilename,
                   offerId: 3,
                 container: "x"},
    function (err, obj) { ...