Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Multipart-POST Request Using Node.js

Multipart-POST Request Using Node.js

Here, I introduce 2 scripts for uploading files to Slack using Node.js as samples. These 2 sample scripts are for uploading files to Slack.

Sample script 1:

  • You can upload the zip file by converting byte array as follows.
    • At first, it builds form-data.
    • Adds the zip file converted to byte array and boundary using Buffer.concat().
    • This is used as body in request.

Basically, this is almost the same to the method using GAS.

var fs = require('fs');
var request = require('request');
var upfile = 'sample.zip';
fs.readFile(upfile, function(err, content){
    if(err){
        console.error(err);
    }
    var metadata = {
        token: "### access token ###",
        channels: "sample",
        filename: "samplefilename",
        title: "sampletitle",
    };
    var url = "https://slack.com/api/files.upload";
    var boundary = "xxxxxxxxxx";
    var data = "";
    for(var i in metadata) {
        if ({}.hasOwnProperty.call(metadata, i)) {
            data += "--" + boundary + "\r\n";
            data += "Content-Disposition: form-data; name=\"" + i + "\"; \r\n\r\n" + metadata[i] + "\r\n";
        }
    };
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"file\"; filename=\"" + upfile + "\"\r\n";
    data += "Content-Type:application/octet-stream\r\n\r\n";
    var payload = Buffer.concat([
            Buffer.from(data, "utf8"),
            new Buffer(content, 'binary'),
            Buffer.from("\r\n--" + boundary + "--\r\n", "utf8"),
    ]);
    var options = {
        method: 'post',
        url: url,
        headers: {"Content-Type": "multipart/form-data; boundary=" + boundary},
        body: payload,
    };
    request(options, function(error, response, body) {
        console.log(body);
    });
});

Sample script 2:

  • fs.createReadStream() can be used as a file for uploading to Slack.
var fs = require('fs');
var request = require('request');
request.post({
    url: 'https://slack.com/api/files.upload',
    formData: {
        file: fs.createReadStream('sample.zip'),
        token: '### access token ###',
        filetype: 'zip',
        filename: 'samplefilename',
        channels: 'sample',
        title: 'sampletitle',
    },
}, function(error, response, body) {
    console.log(body);
});

Result :

Both sample 1 and sample 2 can be uploaded zip file to Slack as follows. For both, even if filetype is not defined, the uploaded file is used automatically as a zip file.

@katio

This comment has been minimized.

Copy link

@katio katio commented Dec 2, 2018

It works like charm. Thx. I just want to mention that Request is a external package: https://github.com/request/request#readme
So first:
npm install --save request

@abhishek200593

This comment has been minimized.

Copy link

@abhishek200593 abhishek200593 commented Aug 21, 2019

Hey I am confused about one thing, the boundary always be changes with each request, so how is it handled here?

@iaravindreddyp

This comment has been minimized.

Copy link

@iaravindreddyp iaravindreddyp commented Nov 7, 2019

Hey I am confused about one thing, the boundary always be changes with each request, so how is it handled here?

i guess it doesn't necessarily have to be different every-time you make a request

@Bneji92

This comment has been minimized.

Copy link

@Bneji92 Bneji92 commented Feb 26, 2020

keep getting this error:

_http_outgoing.js:618 throw new ERR_INVALID_ARG_TYPE('first argument', ^

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string or Buffer. Received type object at write_ (_http_outgoing.js:618:11) at ClientRequest.write (_http_outgoing.js:586:15) at Request.write (C:\Users\Benja\Desktop\Repo\Manager\node_modules\request\request.js:1500:27) at end (C:\Users\Benja\Desktop\Repo\Manager\node_modules\request\request.js:549:18) at Immediate._onImmediate (C:\Users\Benja\Desktop\Repo\Manager\node_modules\request\request.js:578:7) at processImmediate (internal/timers.js:439:21) { code: 'ERR_INVALID_ARG_TYPE' }

@ade-akinyede

This comment has been minimized.

Copy link

@ade-akinyede ade-akinyede commented May 7, 2020

This helped me especially with solving a JWT payload hashing challenge - thank you!

@rakeshnambiar

This comment has been minimized.

Copy link

@rakeshnambiar rakeshnambiar commented Jan 26, 2021

@tanaikech I am trying to make a POST request for curl -X POST "http://myserver-ip-address:9090/api/result" -H "accept: */*" -H "Content-Type: multipart/form-data" -F "allureResults=@allure-results.zip;type=application/x-zip-compressed and the code looks like:

request.post({
    url: 'http://myserver-ip-address:9090/api/report',
    headers: {
        "Content-Type": "multipart/form-data",
        "accept": "*/*"
    },
    formData: {
        file: fs.createReadStream('allure-results.zip'),
        filetype: 'application/x-zip-compressed',
        filename: 'samplefilename',
        channels: 'sample',
        title: 'sampletitle',
    },
}, function(error, response, body) {
    console.log(body);
});

But I am getting the response undefined and I am not sure how to pass allureResults=@allure-results.zip. Please help.

@ccondry

This comment has been minimized.

Copy link

@ccondry ccondry commented Feb 22, 2021

thank you for this code. I was struggling to get node-fetch to work with form-data if I was building a stream from a string instead of from a real file with fs.createReadStream. This helped me build the headers and body manually for a multipart file upload and it finally works.

@ridhuanhassan

This comment has been minimized.

Copy link

@ridhuanhassan ridhuanhassan commented Apr 4, 2021

thank you a lot. I was able to send plain text data with form-data, but I was struggling to send binary data properly until I read this line.

var payload = Buffer.concat([
        Buffer.from(data, "utf8"),
        new Buffer(content, 'binary'),
        Buffer.from("\r\n--" + boundary + "--\r\n", "utf8"),
]);
@spyinfo

This comment has been minimized.

Copy link

@spyinfo spyinfo commented Aug 27, 2021

@tanaikech I am trying to make a POST request for curl -X POST "http://myserver-ip-address:9090/api/result" -H "accept: */*" -H "Content-Type: multipart/form-data" -F "allureResults=@allure-results.zip;type=application/x-zip-compressed and the code looks like:

request.post({
    url: 'http://myserver-ip-address:9090/api/report',
    headers: {
        "Content-Type": "multipart/form-data",
        "accept": "*/*"
    },
    formData: {
        file: fs.createReadStream('allure-results.zip'),
        filetype: 'application/x-zip-compressed',
        filename: 'samplefilename',
        channels: 'sample',
        title: 'sampletitle',
    },
}, function(error, response, body) {
    console.log(body);
});

But I am getting the response undefined and I am not sure how to pass allureResults=@allure-results.zip. Please help.

Hey, did you solve it?

@rakeshnambiar

This comment has been minimized.

Copy link

@rakeshnambiar rakeshnambiar commented Aug 27, 2021

@spyinfo I didn't manage to resolve it. Let me know in case you have any workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment