dannyk
dannyk

Reputation: 259

Slack API (files.upload) using NodeJS

EDITED

I'm trying to structure the files.upload() API provided via Slack but am having a hard time understanding the correct format. At the moment, I am able to use the API to upload a text file but cannot for the life of me figure out how to upload an image.

Here's my issue: I have an image on my development server, let's call it image.png. I want to use the files.upload() API to post that image into a #general Slack channel. Below is the code I have that is successfully generating the image, but currently is just sending the text:

        var myBarChart = new Chart(ctx).Bar(barChartData, barChartOptions);
        var myBarChartDataURL = leaderboardBarChart.toBase64Image();

        canvas.toBuffer(function(err, buf) {
          if (err) throw err;
          fs.writeFile(__dirname + "/leaderboard.png", buf);
        });

        bot.api.files.upload({
          token: process.env.token,
          title: "Image",
          filename: "image.png",
          filetype: "auto",
          //content: "Posted with files.upload API",
          file: fs.createReadStream("path/to/image_file.png"),
          channels: filtered[0].id
        }, function(err, response) {
          if (err) {
            console.log("Error (files.upload) " + err);
          } else {
            console.log("Success (files.upload) " + response);
          };
        });

When I run the code I get one of the following error:

"invalid_array_arg" which Slack details as: "The method was passed a PHP-style array argument (e.g. with a name like foo[7]). These are never valid with the Slack API."

I'm not entirely sure what to make of this error as I'm not using PHP nor anything that I can identify that would be PHP-like.

I've experimented with several different approaches for including the file path, whether using the 'fs' module, storing it in a variable, or just referencing it's absolute path (and even a relative path). I'm a bit lost and am just looking for some guidance.

I understand that this particular API uses multipart/form-data but I don't have a form. This app is strictly a NodeJS app. There is no framework (like Express) working in tandem with the main node script.

Any and all help is really appreciated. Again, just looking for some insight/guidance on what I'm missing or doing wrong.

Thanks in advance!

Upvotes: 11

Views: 11422

Answers (2)

Marco Barcellos
Marco Barcellos

Reputation: 192

I recommend you using the nodejslack. It uses the Promises pattern, powered by Bluebird . There is a sample code for uploading file in its documentations, here it is:

    var Slack = require('nodejslack');
    var fs = require('fs');
    var SLACK_TOKEN = process.env.SLACK_TOKEN || 'YOUR_GENERATED_SLACK_TOKEN';

    var slack = new Slack(SLACK_TOKEN);

    var form = {
      file: fs.createReadStream('test.csv'), // Optional, via multipart/form-data. If omitting this parameter, you MUST submit content 
      // content: 'Your text here', // Optional, File contents. If omitting this parameter, you must provide a `file`  
      filename: 'test.csv', // Required  
      fileType: 'post', // Optional, See more file types in https://api.slack.com/types/file#file_types 
      title: 'Title of your file!', // Optional 
      initial_comment: 'First comment about this file.', // Optional 
      channels: 'general' //Optional, If you want to put more than one channel, separate using comma, example: 'general,random' 
    };

    slack.fileUpload(form)
    .then(function(response){

        // Slack sends a json with a boolean var ok.  
        // Error example : data = { ok: false, error: 'user_not_found'         } 
        // Error example : data = { ok: true, file: 'user_not_found' } 
        if(!response || !response.ok){
            return Promise.reject(new Error('Something wrong happened during the upload.'));
        }
        console.log('Uploaded Successfully:',response);

        return Promise.resolve(response);
    })
    .catch(function(err){
        return err;
    });

Upvotes: 1

user94559
user94559

Reputation: 60153

It looks like you'll have to go outside of Botkit's API here, since Botkit doesn't seem to support sending multipart/form-data.

Give this a try, using request directly (already in use by Botkit itself):

var request = require('request');

...

request.post({
    url: 'https://slack.com/api/files.upload',
    formData: {
        token: bot.config.token,
        title: "Image",
        filename: "image.png",
        filetype: "auto",
        channels: filtered[0].id,
        file: fs.createReadStream('test.png'),
    },
}, function (err, response) {
    console.log(JSON.parse(response.body));
});

Upvotes: 18

Related Questions