1

I am creating node api for user profile update, while uploading file using busboy its showing error Cannot read property "end()" of undefined Below is code of app.js

 app.use(busboy());


  apiRoutes.post('/profileUpdate', function(req, res){
      var token=getToken(req.headers);
      var owner=jwt.decode(token, config.secret);
      var fstream;
      req.pipe(req.busboy);
      req.busboy.on('file', function(fieldname, file, filename){
        var filePath=path.join(__dirname,'public/file', filename);
        fstream=fs.createWriteStream(filePath);
        file.pipe(fstream);
        fstream.on('close', function(){
          console.log("FIle Saved");
        });

      });
    });

I tried to replace app.use(busboy()); but its didn't work. Please help me how to handle this error.

Thanks

Saurabh Sharma
  • 804
  • 6
  • 16
  • 42

2 Answers2

0

is your request multipart/form-data from the front-end where you are trying to upload file? Because Busboy doesn't parse request if it's not multipart/form-data.

ravi
  • 1,130
  • 16
  • 29
0

I am late to the party, but I believe the OP might have the answer figured out by now. Nevertheless its to the people who stumble upon later here

To understand busboy and its implementation, we rather start at the beginning

Multipart Introduction:

In a nutshell , multipart is separating the File info from the data part that you wanted to send to the server. File can be sent as attachment , be it an image or csv and we can attach metadata information for it. This kind of request has a unique boundary that acts as a boundary of chunks and hence a large file can be sent to the server

We place the onus on the server to assemble these chunks by boundary and process them

This is how you usually see a multipart/form-data:

content:type: multipart/form-data; boundary=--------------------------784236237714871062060213
 ----------------------------784236237714871062060213
Content-Disposition: form-data; name="fileName1"; filename="trackReq.csv"
Content-Type: text/csv
.......
.......

Busboy: In order to parse these requests, either we can write our own parser in nodejs with regex, experiment and come up with a solution or we can use packages like busboy, formidable (which are framework agnostic) and multer, express-file-upload(which are framework native)

Busboy works with the multipart requests and it intends the request to have a header 'content-type' as 'multipart/form-data' (sometimes the ones with 'Content-Type' doesn't work. You have manually make sure you convert the request header to smaller case during it)

How to use it:

 Busboy is built on top of event emitter stream implementation. You have to make sure that you use the readable stream to pipe the info to writableStream, listen to their respective events (There are lot of sources explaining how a stream works in nodejs and [this][1] here is a great place to get started)

This is a sample implementation with aws-lambda, event being an APIGatewayProxyEvent

 let contentType = event.headers['content-type']
            if (!contentType) {
                contentType = event.headers['Content-Type'];
            }
            console.log('content:type:', contentType)
            const writeStream  = fs.createWriteStream(path.join(process.cwd(), './src/assets/files/XXXX.csv'))


            const readStream = Readable.from(event.body);
            const bb = busboy({ headers: {'content-type': contentType} });
            Readable.from(event.body).pipe(bb);
            bb.on('file', (fieldname, file,filename, encoding, mimetype ) => {
                file.on('data', (data) => {
                    console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
                    writeStream.write(data);
                });
                file.on('end', function(data) {
                    console.log('File [' + fieldname + '] Finished', data);
                    writeStream.end(() => {
                        console.log('completed writing')
                    })
                });


                writeStream.on('error', err => {
                    console.log('receveied error:', err);
                    //TODO: write this to the callback or return statement
                })

            })
            bb.on('error', error => {
                console.log('busboy err:',error);
            });
            bb.on('finish', function() {
                console.log('completed')
            });

To answer the OP's question, first a busboy refernce should be created with headers pointing to content-type as 'multipart/form-data' and that should be piped to the req, like this. Again this is purely in the context of a server implementation (I've also provided the serverless implementation above)

const bb = busboy({headers: {'content-type':'multipart/form-data'}});
req.pipe(bb)
vijayakumarpsg587
  • 1,079
  • 3
  • 22
  • 39