3

I've an API in Node and Express which is receiving a file from a the client (Postman in development) and I use multer to get the file in memory like this:

router.post('/api/v1/upload', contrl.upload, contrl.uploadFile);

and then in my controller:

exports upload = multer({ storage: multer.memoryStorage() }).single('file');

Now I can access the file with req.file.buffer, but then I want to send this same file to another API. I'm using request-promise-native so this would be something like this:

const rp = require('request-promise-native')

exports.uploadFile = (req, res) => {

  const options = {
    method: 'POST',
    uri: `${uri}`,
    form: {
      file: req.file.buffer
    }
  }

  rp(options)
    .then(parsedBody => {
      return res.status(201).send(parsedBody);
    })
    .catch(err => res.status(400).send(err));
}

I removed some other params for simplicity, but this is not working, probably because Node doesn´t know how to handle the info inside req.file.buffer.

EDIT. Ok after some tests I tried to make this work with a real file instead of using multer memoryStorage. So I got this:

exports upload = multer({ dest: 'uploads/' }).single('file');

to save the file to disk, and then

const request = require('request')

exports.uploadFile = (req, res) => {

  const formData = {
    file: fs.createReadStream('uploads/' + req.file.filename)
  }
  const options = {
    url: `${uri}`
    formData
  }

  request.post(options, (err, response, body) => {
    if (err) return res.status(400).send(err);
    return res.status(201).send(response);
  });
}

And it works! But then when I change to memoryStorage in multer and I use file: req.file.buffer instead, it does not work.

EDIT2: I also tried to send the file as a stream when in memory, so I tried this

const bufferStream = new stream.PassThrough();
bufferStream.end(req.file.buffer);

and then passing it in the formData with file: bufferStream but also not working.

How can I achieve this? Thanks

5 Answers 5

3

I had the same problem a few times and always end up with a bad solution. thank you all for this post. Here is my solution with aixios in case someone can use it

//First use form-data
const FormData = require('form-data') ;
//use axios
const axios = require('axios') ;


//Note is very important passing contentType and filename 
//options
let form = new FormData() ;
//consider req.file is the file coming from multer
form.append('file',req.file.buffer,{
     contentType:req.file.mimetype,
     filename:req.file.originalname
  }) ;


//now do a post request with axios
// personally I like the use of async-await for promises but
//then() catch() will work just fine
let response = await axios.post('API_URL', form, {
  headers: form.getHeaders() 
});
// whatever you need with response ex.
console.log(response.data)
Sign up to request clarification or add additional context in comments.

Comments

2

I recently encountered a similar situation,My process:web to node to PHP.I use "multer" and "request" resolve this problem and i don't use real file.

    const multer  = require('multer')
    const upload = multer();
    const request = require('request');

    router.post('/upload', upload.single('img'),(req,res,next) => {

        let formData = {
            'quality':80,
            //file field need set options 'contentType' and 'filename' for formData
            'file':{
                value:req.file.buffer,
                options:{
                    contentType:req.file.mimetype,
                    filename:req.file.originalname
                }
            }
        }    
       request.post({
             url:''/**uploadurl*/,
             formData
       },function(err,response,body){res.send(body)})
    })

Comments

0
const rp = require('request-promise-native')

exports.uploadFile = (req, res) => {

  const options = {
    method: 'POST',
    uri: `${uri}`,
    formData: {
      file: req.file.buffer
    }
  }

  rp(options)
    .then(parsedBody => {
      return res.status(201).send(parsedBody);
    })
    .catch(err => res.status(400).send(err));
}

7 Comments

I get an error. Do I need some special header or something? In the response I can see "error": "Bad Request", "options": { "method":"POST", "uri": "....", "file": "cHJ1ZWJh=="}
check the API that you are calling. They probably expect the request to be done in a certain way.
Nothing special. The API works fine if I use Postman and send a POST request with form-data and the file as File. When I inspect the request payload I get Content-Type: text/plain for the file, but if I use the above mechanism it's a binary object, so I'm guessing something is not quite right and the API does not know how to interpret this
When you use base64 encoding you are sending plain text, not binary data. If you dont use base64 encoding what happen?
If I don´t use base64 then this is what I see in the request header "form": { ... "file": { "type": "Buffer", "data": [ 112, 114, 117, 101,... ]}}" and the same error from the API
|
0

This should solve your problem

const http = require('http');
exports.uploadFile = (req, res) => {
    // create new request to reupload file
    const request = http.request({  
        port : 80,
        hostname : '127.0.0.1',
        method : 'POST',
        path : '/'
    });
    let result = '';
    // grab response from new request
    request.on('data', (chunk) => {
        result += chunk;
    });
    // resend response from new request
    request.on('end', () => {
        res.status(201).end(result);
    });
    // resend error from new request
    request.on('error', (err) => {
        res.status(400).end(err);
    });
    // pipe your file to new request
    req.file.stream.pipe(request);
};

Comments

0

Use Node Memory Streams https://www.npmjs.com/package/memory-streams

var streams = require('memory-streams')
  , fs      = require('fs');

// Pipe  
var reader = fs.createReadStream('index.js');
var writer = new streams.WritableStream();
reader.pipe(writer);
reader.on('readable', function() {

  // Output the content as a string 
  console.log(writer.toString());

  // Output the content as a Buffer 
  console.log(writer.toBuffer());
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.