Convert curl upload files to request in Node.JS and write zip file

3.4k Views Asked by At

I am trying to convert the following curl to node request.

curl -F files[][email protected] 'https://www.rebasedata.com/api/v1/convert?outputFormat=mysql&errorResponse=zip' -o output.zip

I have tried using request or node-libcurl but can't find a way to upload a mdb file.

The code I have is

var request = require('request');

var options = {
    url: 'https://www.rebasedata.com/api/v1/convert?outputFormat=mysql&errorResponse=zip',
    method: 'POST',
    formData: {
        custom_file: {
            options: {
            contentType: 'application/mdb'
        },
            value: path.resolve(__dirname, 'myMdb.mdb') 
        }
    }
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);

But I kept getting error like no files given or couldn't open file.

Any help is appreciated.

2

There are 2 best solutions below

3
On BEST ANSWER

You have some errors:

Edited: How to write zip file from resoponse?

You want to write zip file, please reference package JSZip https://stuk.github.io/jszip/documentation/howto/read_zip.html. After have body, read zip and write to zip file.

I've done your problem with new code, the callback handler is from document of request, you can ignore my callback handler.

Updated zip file

Before please install package jszip

npm install jszip --save

And this is code, please add encoding: null when request:

var request = require('request');
var path = require('path');
var fs = require('fs');
var JSZip = require("jszip");

function callback(error, response, body) {
    if (error || response.statusCode !== 200) {
        console.log(error);
        return;
    }
    JSZip.loadAsync(body).then(zip => {
        console.log(zip.files);
        zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
            .pipe(fs.createWriteStream(path.join(__dirname, './out.zip')))
            .on('finish', function () {
                console.log("File written");
            });
    }).catch(err => console.log(err))
}

request({
    url: 'https://www.rebasedata.com/api/v1/convert?outputFormat=mysql&errorResponse=zip',
    method: 'POST',
    encoding: null, // <--------- important ----------
    formData: {
        'files[]': {
            options: {
                filename: 'database.mdb',
                contentType: 'application/mdb'
            },
            value: fs.createReadStream(path.resolve(__dirname, './database.mdb'))
        }
    }
}, callback);

My file database.mdb is uploaded here https://ufile.io/prnsi (file will be deleted after 30 days from the answer posted).

And when console.log(zip.files);, you'll receive from my database file

{ 'data.sql':
   { name: 'data.sql',
     dir: false,
     date: 2018-12-17T02:09:08.000Z,
     comment: null,
     unixPermissions: 33206,
     dosPermissions: null,
     _data:
      { compressedSize: 643,
        uncompressedSize: 1817,
        crc32: 1832401262,
        compression: [Object],
        compressedContent: <Buffer 9d 54 6d 6f a2 40 10 fe 7c fc 8a b9 4f da 56 da c5 7a 46 bd 98 88 b0 b6 44 5c ae 80 f7 d2 2f 88 b0 6d 49 10 1a 5e 9a f6 df df 02 be 80 40 7a 39 02 c9 ... > },
     _dataBinary: true,
     options: { compression: null, compressionOptions: null } } }
2
On

It looks like you might have two issues:

  1. If the curl statement is correct, then the server is expecting the form field containing the file to be called files[], not custom_file as you have in your nodejs example.

  2. You are passing a string (the name of the file), not a stream (the contents of the file).

Try something like this:

var request = require('request');

var options = {
    url: 'https://www.rebasedata.com/api/v1/convert?outputFormat=mysql&errorResponse=zip',
    method: 'POST',
    formData: {
        'files[]': {
            options: {
                contentType: 'application/mdb'
            },
            value: fs.createReadStream(path.resolve(__dirname, 'myMdb.mdb'))
        }
    }
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);

(I'd also look into https://github.com/request/request-promise; it has the same request format but you can ditch the callbacks and use promises instead, which is considered idiomatic and will be easier in the long run.)