Skip to content
This repository has been archived by the owner on Sep 14, 2022. It is now read-only.

Someone can post an example of how implement file upload on a controller #265

Closed
oliverhr opened this issue Aug 3, 2015 · 17 comments
Closed

Comments

@oliverhr
Copy link

oliverhr commented Aug 3, 2015

Please help!

I tried with fs and multer, but I could not make it work.

Note: Is an express project and was generated using swagger-project (last version).

'use strict';

var debug = require('debug')('api:fileupload');
var upload_file = require('multer');

module.exports = {
  upload: upload
};

var supported_mimes = [
  'image/png',
  'image/jpeg',
  'image/gif'
];

upload_file({ dest: './uploads/images/'});

function upload(req, res, next) {
  debug(req.files);

  var file = req.swagger.params.file.value;

  if (supported_mimes.indexOf(file.mimetype) === -1) {
    debug('File not supported for upload');
    var err = {
      message: 'File type not supported for uploads'
    };
    return next(err);
  }

  var data = {
    'id': file.name.substr(0, file.name.lastIndexOf('.')),
    'extension': file.extension,
    'size': file.size
    'type': file.mimetype
  };

  // repetitive but...
  // upload_file({ dest: './uploads/images/'});

  res.json(data);
}

My Debug output

{
   file: {
     fieldname: 'file',
     originalname: '94ad1e5eef59a88ab1497197701a7a77.jpg',
     name: '06d75d3c767b0e5a2a0ff8213edfecbc.jpg',
     encoding: '7bit',
     mimetype: 'image/jpeg',
     path: '/var/folders/.../06d75d3c767b0e5a2a0ff8213edfecbc.jpg',
     extension: 'jpg',
     size: 54859,
     truncated: false,
     buffer: < Buffer ff d8 ff e0 00 10 4 a 46 49 46 00 01 01 01 00 48 00... >
   }
}

thank you in advance.

@theganyo
Copy link
Contributor

theganyo commented Aug 4, 2015

Based on your output, it looks like you did receive the file. Have you attempted to just access the file via file.path or the file data via file.buffer?

@oliverhr
Copy link
Author

oliverhr commented Aug 5, 2015

Hi Scott,

What I've finishing doing is:

...
var upload  = require('multer')({ dest: 'uploads/' });
...
// Project generated with swagger-project
// swagger file: api/swagger/swagger.yaml

SwaggerExpress.create(config, function(err, swaggerExpress) {
  if (err) { throw err; }

  // Generic middleware for file upload 
  app.use(upload.single('file'));

  // install middleware
  swaggerExpress.register(app);

  ...

I don't want this middleware to be applied for all the routes, so reformulating my question is :

How add PRE and/or POST middleware to swagger per routes?

I read some similar and say that "...is handled by #209"

If you can provide an example it would be great.

@whitlockjc
Copy link

multer is built into swagger-node via swagger-tools so you shouldn't need to mess with it unless you need a custom configuration. That being said, what was wrong with using the file produced by multer via req.swagger.params.file.value? We already conditionally load the parsers so it's not involved in all route handlers and is only used when required so since you got the file object from req.swagger.params.file.value and it's already pre-configured to work as you want, why all the extra effort?

If you're trying to tell me what you're trying to do, I am sure I can whip up an example or at least point you in the right direction.

@whitlockjc
Copy link

Also, it seems you're using multiple different versions of multer. The one we use in swagger-tools/swagger-node is 0.1.8 and the API changed drastically in 1.0.x.

@oliverhr
Copy link
Author

oliverhr commented Aug 5, 2015

Hi Jeremy,

Yes you are right, in fact in this moment I was reading "swagger-tools/swagger-tools/swagger-metadata.js" – Yes too old multer version –,

why all the extra effort?
I don't found documentation about how files are handled by swagger-node, I just assumed that file handling responsibility was fully mine.

what was wrong with using the file produced by multer via req.swagger.params.file.value?
My first aprouch was with fs move/copy the file from file.path, file does not exist, now Im writing the buffer to a file.

Well then. If another insomniac like mine, would fall in the same thing:

... 
  var path = 'uploads/';
  fs.writeFile( path + file.name, file.buffer , function (err) {
    if (err) {
      debug(err);
      var err = {
        message: 'File not uploaded'
      };
      return next(err);
    }
  });
...

Quoting Jeremy by the way: paths must be relative to process.cwd, so in the example the file is saved on project_root/upload/filename.ext.

Sorry, I have a couple of days with swagger and my starting point was swagger-node plus so few caffeine or maybe too much.

@whitlockjc , @theganyo – guys thank you very much.

@oliverhr oliverhr closed this as completed Aug 5, 2015
@whitlockjc
Copy link

I'm glad you got it sorted.

@whitlockjc
Copy link

I will likely update multer in swagger-tools' next release but it should work fine as-is. If the current version is causing you issues, let us know. As for your solution, that is how I would handle it, using the file buffer to write to where I needed. I do know with multer you can specify the upload location but that seems to be very implementation specific so I took a more general approach.

@oliverhr
Copy link
Author

oliverhr commented Aug 5, 2015

Yes I agree with you. For now I'm saving files locally but indeed using this approach (buffer or stream) is better and when needed to switch to a cloud storage the impact on code changes and performance will be meaningless.

@MaksymRadko
Copy link

Hi! I'm using swagger request validation tool and multer, but after using swagger validate req I already have req.files fulfilled and my multer does not handle anything. When I don't use swawgger validation all works fine. How can I solve this problem?

@oliverhr
Copy link
Author

@MaksymRadko what swagger request validation tool?

@robertoclavijob
Copy link

@oliverhr your comments helped me a lot, thanks mate!

@oliverhr
Copy link
Author

Your are welcome @robertoclavijob, Im glad to hear that.

@rramanadham
Copy link

Hi everyone,
I need to save large files in mongodb using gridfs.
And I have the same problem as MaksymRadko.
The problem is if I use swagger validator, multer doesn't store the file in mongoDB. But I have access to my metadata parameter.

If I don't use swagger and just call my controller, I can't find the metadata parameter. Can anyone please explain what I am doing wrong.

I use swagger-tools: 0.10.4, swagger-ui-express:2.0.15, multer-gridfs-storage:3.3.0, multer: 1.4.2

Here is my swagger spec params :

 "parameters": [
    {
      "name": "file",
      "in": "formData",
      "type": "file",
      "required": true
    },
    {
      "name": "metadata",
      "in": "formData",
      "type": "string",
      "required": true
    }

//My app.js snippets using swagger middleware
const path = require('path'),
http = require('http'),
app = require('express')(),
swaggerTools = require('swagger-tools');

swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools //middleware chain
app.use(middleware.swaggerMetadata());

// Validate Swagger requests
app.use(middleware.swaggerValidator());

// Route validated requests to appropriate controller
app.use(middleware.swaggerRouter(options));
logger.info('Successfully loaded all the routes');

_.forEach(appMWs.setupSwaggerRoutes(specUtil.getBaseURL(), swaggerDoc), (middleware) => {
    app.use(middleware.uripath, middleware.router);
});

// Start the server
http.createServer(app).listen(serverPort, function () {
    logger.info('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
    logger.info('Swagger-ui is available on http://localhost:%d%s/api-docs', serverPort, specUtil.getBaseURL());
});

});

//my controller

const crypto = require('crypto');
const path = require('path');
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');

async function uploadFile(req,res,next){
//we can get metadata only if we go via swagger validator
//we don't have req.body when we bypass swagger middlewares.
let metadata = JSON.parse(req.body.metadata);

try{
    let file = req.files.file[0];
    let storage = new GridFsStorage({
        url: 'mongodb://localhost:27017/file-upl?useUnifiedTopology=true&useNewUrlParser=true',
        cache: true,
        file: (req, file) => {
            return new Promise((resolve, reject) => {
                crypto.randomBytes(16, (err, buf) => {
                    if (err) {
                        return reject(err);
                    }
                    const filename = buf.toString('hex') + path.extname(file.originalname);
                    const fileInfo = {
                        filename: filename,
                        bucketName: 'uploads',
                        metadata:metadata
                    };
                    resolve(fileInfo);
                });
            });
        }
    });

    let upload = multer({storage}).single('file');
}
catch(err){
    next(err);

}

}

Can any one help as to what's going on? Have been stuck for more than a week now.
Thanks!

@rramanadham
Copy link

@MaksymRadko were you able to solve the problem

@rodriguesnavil
Copy link

rodriguesnavil commented Jul 3, 2020

@whitlockjc @theganyo @oliverhr Thank you so much, the above comments helped me a lot!

@oliverhr
Copy link
Author

oliverhr commented Jul 4, 2020

Hi @rodriguesnavil good to hear, I don't use anymore this library (I leave the project where I use it), seems a little bit unmaintained, don't know if there are more new alternatives, but if you need help with this ping me, I don't promise to know all the answers but if I can help you I'll do :)

@rodriguesnavil
Copy link

Hi @rodriguesnavil good to hear, I don't use anymore this library (I leave the project where I use it), seems a little bit unmaintained, don't know if there are more new alternatives, but if you need help with this ping me, I don't promise to know all the answers but if I can help you I'll do :)

Thank you for your kind words, I'll surely ping you if I get stuck somewhere :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants