node.jscloudflareform-data

Error uploading image to Cloudflare from Buffer with node js and FormData


I am trying to upload an image to Cloudflare from a buffer. I am using the following code:


const cloudflare_url = `https://api.cloudflare.com/client/v4/accounts/${process.env.CLOUDFLARE_ACCNT_ID}/images/v1`;
const roundedCorners = Buffer.from('<svg><rect x="0" y="0" width="200" height="200" rx="50" ry="50"/></svg>');
const form = new FormData();
form.append("file", roundedCorners, "test/corners");
console.log(form.getLengthSync());

const headers = {
  Authorization: `Bearer ${process.env.CLOUDFLARE_API_KEY}`,
  ...form.getHeaders(),
  "content-length": form.getLengthSync(),
};

const response = await fetch(cloudflare_url, {
  method: "POST",
  headers,
  body: form,
});

const result = await response.json();
console.log(result);
if (result.success) console.log(`File transferred successfully!`);
else console.log(`Failed to transfer file`);

With the code above, I get the error

Request body length does not match content-length header

If I remove the line "content-length": form.getLengthSync()", I get the error:

'Bad request: incomplete multipart stream'

If I convert the buffer to a Blob before appending it to the form, I get the error:

source.on is not a function

I am at a loss. Do you see anything wrong with the code above or have any alternative solutions?


Solution

  • You can use the npm cloudflare package instead.

    Option 1. Create Client using your API Key & Email Address

    import Cloudflare from 'cloudflare';
    
    const client = new Cloudflare({
       apiEmail: process.env['CLOUDFLARE_EMAIL'], // This is the default and can be omitted
       apiKey: process.env['CLOUDFLARE_API_KEY'], // This is the default and can be omitted
    });
    

    Option 2. Create Client using a Token (preferred). Token needs to be generated by navigating to:

    import Cloudflare from 'cloudflare';
    
    const client = new Cloudflare({
      apiToken: process.env['CLOUDFLARE_TOKEN'], // add token string to process.env
    });
    

    Since you are not reading an image from your file system and instead you want to create an svg from a string you will need jsdom.

    Now you can create the svg within a JSDOM, extract the svg, convert to binary and send:

    import Cloudflare from 'cloudflare';
    import {JSDOM} from 'jsdom';
    
    const client = new Cloudflare({
        apiToken: process.env['CLOUDFLARE_TOKEN']
    });
    
    const str = '<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="200" height="200" rx="50" ry="50" fill="blue"/></svg>';
    const dom = new JSDOM(`<!DOCTYPE html><html><body>${str}</body></html>`);
    const elem = dom.window.document.querySelector('svg');
    const imgBinary = Buffer.from(elem.outerHTML).toString('binary');
    
    const image = await client.images.v1.create({
        account_id: yourIdHere,
        file: imgBinary
    });
    
    console.log(image.id);