docs icon indicating copy to clipboard operation
docs copied to clipboard

Need documentation for uploading multiple files: Uploading files (guides/advanced/file-uploading.md)

Open dmklsv opened this issue 7 years ago • 5 comments

My src/services/uploads/uploads.service.js

// Initializes the `uploads` service on path `/uploads`
const createService = require('feathers-rethinkdb');
const hooks = require('./uploads.hooks');

// feathers-blob service
const blobService = require('feathers-blob');
// Here we initialize a FileSystem storage,
// but you can use feathers-blob with any other
// storage service like AWS or Google Drive.
const fs = require('fs-blob-store');

const multer = require('multer');
const multipartMiddleware = multer();


// File storage location. Folder must be created before upload.
// Example: './uploads' will be located under feathers app top level.
const blobStorage = fs('./uploads');

module.exports = function (app) {
  const Model = app.get('rethinkdbClient');
  const paginate = app.get('paginate');

  const options = {
    name: 'uploads',
    Model,
    paginate
  };

  // Upload Service with multipart support
  app.use('/uploads',

    // multer parses the file named 'uri'.
    // Without extra params the data is
    // temporarely kept in memory
    multipartMiddleware.array('uri', 2),

    // another middleware, this time to
    // transfer the received file to feathers
    function(req,res,next){
        req.feathers.file = req.file;
        next();
    },
    blobService({Model: blobStorage})
);

  // Get our initialized service so that we can register hooks and filters
  const service = app.service('uploads');

  service.hooks(hooks);

};

My src/services/uploads/uploads.hooks.js

const dauria = require('dauria');

const { authenticate } = require('@feathersjs/authentication').hooks;

module.exports = {
  before: {
    all: [],
    find: [],
    get: [],
    create: [
        function(context) {
            if (!context.data.uri && context.params.file){
                const file = context.params.file;
                const uri = dauria.getBase64DataURI(file.buffer, file.mimetype);
                context.data = {uri: uri};
            }
        }
    ],
    update: [],
    patch: [],
    remove: []
  },

  after: {
    all: [],
    find: [],
    get: [],
    create: [ ],
    update: [],
    patch: [],
    remove: []
  },

  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  }
};

My dropzonejs code

            Dropzone.options.myDropzone = {
                paramName: function() { return 'uri'; },
                uploadMultiple: true,
                autoProcessQueue: false,
                maxFiles: 2,
                method: 'post',
                init: function(){
                  myDropzone = this;
                    this.on('uploadprogress', function(file, progress){
                        console.log('progresss', progress);
                    });
                }
            };

I'm trying to upload several files but I get an error in the console

error: TypeError: Cannot read property 'startsWith' of undefined at Dauria.parseDataURI (/Volumes/HomeHD/Projects/Eomoe/node_modules/dauria/dauria.js:27:18) at Object.create (/Volumes/HomeHD/Projects/Eomoe/node_modules/feathers-blob/lib/index.js:87:52) at processHooks.call.then.hookObject (/Volumes/HomeHD/Projects/Eomoe/node_modules/@feathersjs/feathers/lib/hooks.js:67:27) at at process._tickCallback (internal/process/next_tick.js:188:7)

P.S. multipartMiddleware.single('uri'), everything works well with one file

dmklsv avatar Jan 19 '18 17:01 dmklsv

I am facing the same problem as you are now. 2 issues in your code that I can see are:

  1. req.file is undefined because you use multer array so instead of req.file you should use req.files
  2. the same should be applied to your before hook. instead of accessing context.params.file you should access context.params.files

this is the place where I am stuck BTW.

ranhsd avatar Apr 18 '18 14:04 ranhsd

I'm facing the sambe problem anyone could help ?

My upload.service.js // Initializes the upload service on path /upload const createService = require("feathers-nedb"); const createModel = require("../../models/upload.model"); const hooks = require("./upload.hooks"); const blobService = require("feathers-blob"); const fs = require("fs-blob-store"); const blobStorage = fs("./uploads"); const multer = require("multer"); const multipartMiddleware = multer();

module.exports = function() { const app = this; const Model = createModel(app); const paginate = app.get("paginate");

// Initialize our service with any options it requires app.use( "/uploads", multipartMiddleware.single("uri"), function(req, res, next) { req.feathers.file = req.file; next(); }, blobService({ Model: blobStorage }) );

// Get our initialized service so that we can register hooks and filters const service = app.service("uploads");

service.hooks(hooks); };

My upload.hooks.js const dauria = require("dauria"); module.exports = { before: { all: [], find: [ context => { console.log(context); } ], get: [], create: [ context => { if (!context.data.uri && context.params.file) { const file = context.params.file; const uri = dauria.getBase64DataURI(file.buffer, file.mimetype); context.data = { uri: uri }; } } ], update: [], patch: [], remove: [] },

after: { all: [], find: [], get: [], create: [], update: [], patch: [], remove: [] },

error: { all: [], find: [], get: [], create: [], update: [], patch: [], remove: [] } };

i'm getting this error error: Error: Unexpected field at makeError (C:\Desenvolvimento\uploadService\node_modules\multer\lib\make-error.js:12:13) at wrappedFileFilter (C:\Desenvolvimento\uploadService\node_modules\multer\index.js:40:19) at Busboy. (C:\Desenvolvimento\uploadService\node_modules\multer\lib\make-middleware.js:114:7) at emitMany (events.js:147:13) at Busboy.emit (events.js:224:7) at Busboy.emit (C:\Desenvolvimento\uploadService\node_modules\busboy\lib\main.js:38:33) at PartStream. (C:\Desenvolvimento\uploadService\node_modules\busboy\lib\types\multipart.js:213:13) at emitOne (events.js:116:13) at PartStream.emit (events.js:211:7) at HeaderParser. (C:\Desenvolvimento\uploadService\node_modules\dicer\lib\Dicer.js:51:16)

Nyeedz avatar Jun 01 '18 17:06 Nyeedz

Uhm I'm stuck here too lol, it uploads it with no errors, but it doesn't save in storage and when debugging I don't see any files in the hook. It does work with custom express middleware... Even with a single file it doesn't save it in storage though, maybe I'll create a new issue for this if I can't solve it

Aeroxander avatar Sep 24 '18 01:09 Aeroxander

Getting this too. Also I don't get why we need the

const Model = createModel(app);
const paginate = app.get("paginate");

It's never used....

bitflower avatar Jan 18 '19 08:01 bitflower

Ok, got it working. It works as follows: multer checks of the property where the file is put matches the name given to the .single() call (in this case "uri"):

app.use('/files',

        // multer parses the file named 'uri'.
        // Without extra params the data is
        // temporarely kept in memory
        multipartMiddleware.single('uri'),

        // another middleware, this time to
        // transfer the received file to feathers
        function (req, res, next) {
            debug('multi-middleware', req);
            req.feathers.file = req.file;
            next();
        },
        blobService({ Model: blobStorage })
    );

This check is here inside multer: bildschirmfoto 2019-01-18 um 19 01 45

When you set all this up correctly you can post a file via Postman: bildschirmfoto 2019-01-18 um 19 04 01

See the use of "uri" in the 2 spots.

The "Unexpected field" string is the LIMIT_UNEXPECTED_FILE const.

bitflower avatar Jan 18 '19 18:01 bitflower