Search code examples
node.jsaxioscontent-type

How to post an image as a File with Axios after Getting it as an Arraybuffer from an attachment


As a POC I would like to make pictures of my receipts (gas, shop etc) and use a chatbot to send them to my accounting software. My problem has to do with the sending of the collected receipt (an image) to the accounting software using its API.

The first part (getting the attachment) results in an Arraybuffer with an image. I used one of the NodeJS samples for that (nr 15).

    const attachment = turnContext.activity.attachments[0];
    const url = attachment.contentUrl;
    let image;
    axios.get(url, { responseType: 'arraybuffer' })
        .then((response) => {
            if (response.headers['content-type'] === 'application/json') {
                response.data = JSON.parse(response.data, (key, value) => {
                    return value && value.type === 'Buffer' ? Buffer.from(value.data) : value;
                });
            }
            image = response.data;
        }
        ).catch((error) => {
            console.log(error);
        });

I am struggling with the second part. Posting the image to the accounting software

const requestConfig = {
        headers: {
            'Authorization': 'Bearer ' + accessToken,
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    };
    axios.post(postUrl, image, requestConfig)
        .then((response) => { console.log(response); }
        ).catch((error) => {
            console.log(error);
        });
};

This results in 400. bad request. Probably the API needs a file and I cannot just send the buffer. I tested with Postman and the request is accepted by using application/x-www-form-urlencoded (by using a locally stored image file).

What is best practice to post an image retrieved in a bufferarray?


Solution

  • I think your comment is right on the money that you need to convert it to a file first. The channel isn't an issue because the file will be stored wherever the bot is hosted. The Attachments Sample actually has this code, which gets you close:

    fs.writeFile(localFileName, response.data, (fsError) => {
        if (fsError) {
            throw fsError;
        }
        // Send the file
        const url = '<yourApiUrl>';
        const formData = new FormData();
        formData.append('file',fs.createReadStream('<pathToFile>'), { knownLength: fs.statSync('<pathToFile>').size });
        const config = {
            headers: {
                ...formData.getHeaders(),
                'Content-Length': formData.getLengthSync()
            }
        };
        axios.post(url, forData, { headers });
    });
    

    I'm not super confident in the // Send the file section only because I can't test against your API. I got most of the code from here.