Convert a binary to base64 or send multipart/form-data

Hello dear friends,

is there a way to convert a binary file which I’ve retrieved inside a Action Button Script using the Fibery File API to a Base64 format, also inside the same Script?

Or, another option for me, would be to send this binary file through the http.postAsync using a “multipart/form-data” content-type

See the two options bellow, please

// OPTION 1 - send a binary file to a external API using a multipart/form-data Content-type

for (const file of files['Files']) {

	const fileWithSecret = await fibery.getEntityById("fibery/file", file['id'], ["Secret", "Name", "Content Type"]);
	const fileUrl = "http://<mydomain>.fibery.io/api/files/" + fileWithSecret["Secret"];

	const f = await http.getAsync(fileUrl, { 'headers': { 'Authorization': 'Token mytoken' } });
	
	// here is the external API to where I need to send the file 
	const responseArquivo = await http.postAsync('https://myexternalapi', {
		body: // HOW DO I PASS multipart/form-data HERE? ... let's say I have two keys here: file_name and file (the binary itself)
			
		,
		headers: {
			'Content-type': 'multipart/form-data',
			'apikey': 'xxxxx'
		}
	});

}


// OPTION 2 - send a BASE64 to a external API using a application/json Content-type

for (const file of files['Files']) {

	const fileWithSecret = await fibery.getEntityById("fibery/file", file['id'], ["Secret", "Name", "Content Type"]);
	const fileUrl = "http://<mydomain>.fibery.io/api/files/" + fileWithSecret["Secret"];

	const f = await http.getAsync(fileUrl, { 'headers': { 'Authorization': 'Token mytoken' } });
	
	// here is the external API to where I need to send the file 
	const responseArquivo = await http.postAsync('https://myexternalapi', {
		body: {
			filename: fileWithSecret["Name"],
			file: // HERE I NEED A BASE64 string representation of the file
		}
		,
		headers: {
			'Content-type': 'application/json',
			'apikey': 'xxxxx'
		}
	});

}

To get base64, you can use the javascript btoa function.

I tryed but it didn’t work.

image

image

Hi guys, so far I wasn’t able to accomplish this.

I even look for some plain algortims to convert to base64 but it didnt work too :frowning:

Hey @adrielmoro,

the function btoa does not exist in the reduced Fibery sandbox environment for the Script action. An alternative is the Buffer.from function available in Node, however the Buffer keyword is also not part of the Fibery script environment. You therefore have to paste the following code into your script action, which implements base64 encoding from scratch.

I took it from an npm package and adjusted it so that it can run inside the Fibery Script action:

const base64Characters =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

function textToBinary(text) {
  let binaries = "";

  for (let i = 0; i < text.length; i++) {
    const letterBinary = text.charCodeAt(i).toString(2);
    const letterBinary8Bits = letterBinary.padStart(8, "0");
    binaries += letterBinary8Bits;
  }

  return binaries;
}

function groupBinariesByNumberOfBits(binary, quantityOfBits) {
  const regex = new RegExp(`.{1,${quantityOfBits}}`, "g");
  const groupedBinaries = binary.match(regex);
  const binariesWithQuantityOfBits = groupedBinaries.map((binary) =>
    binary.padEnd(quantityOfBits, "0")
  );

  return binariesWithQuantityOfBits;
}

function binaryToDecimal(binary) {
  const decimal = parseInt(binary, 2);
  return decimal;
}

function binaryToBase64(binary) {
  const groupedBinaries = groupBinariesByNumberOfBits(binary, 6);
  const base64 = groupedBinaries.map((binary) => {
    const decimal = binaryToDecimal(binary);
    return base64Characters[decimal];
  });

  const base64ArrayAsString = base64.join("");
  return base64ArrayAsString;
}

function addEndChar(text, base64) {
  const remainderMultipleOf3 = {
    0: "",
    1: "==",
    2: "=",
  };

  const remainder = text.length % 3;
  const base64WithEndChar = base64.concat(remainderMultipleOf3[remainder]);
  return base64WithEndChar;
}



function base64Encode(text) {
  if (!text) return text;

  let data = "";
  data = text;
  const binary = textToBinary(data);
  const base64 = binaryToBase64(binary);
  const base64WithEndChar = addEndChar(data, base64);
  return base64WithEndChar;
}

// Example: this correctly prints 'dGVzdA=='
console.log(base64Encode("test"));

You can now use the function base64Encode to base64 encode any string inside your Script action :+1:

1 Like

Hi there @derbenoo … thanks a lot for your attention on this.

Sorry for the delayed answer, got some other issues here and only now I’m returning on this.

I’ve tested the script you’ve shared and it works well with text data :slightly_smiling_face:.

But I’m downloading a binary file, like in the code below.

I’ve also tested with others scripts I’ve found on the internet that deals with binary ones. It didn’t work too. I’m suspecting the function “await http.getAsync(fileUrl, { ‘headers’: { ‘Authorization’: ‘Token mytoken’ } });” is somehow messing the content up before returning the result, perhaps forcing it to a string type. I’m not sure. I couldn’t figure it out.


for (const entity of args.currentEntities) {

    try {

        const files = await fibery.getEntityById(entity.type, entity.id, ['Files']);

        for (const file of files['Files']) {


            const fileWithSecret = await fibery.getEntityById("fibery/file", file['id'], ["Secret", "Name", "Content Type"]);
            const fileUrl = "http://mydomain.fibery.io/api/files/" + fileWithSecret["Secret"];

            // download file (perhaps here the things are getting wrong)
            const f = await http.getAsync(fileUrl, { 'headers': { 'Authorization': 'Token mytoken' } });

            const base64EncodedFile = base64Encode(f) // here your original function expects a text instead of a binary

            //console.log(['tipo', Object.prototype.toString.call(f)]);
            console.log(['File in b64', base64EncodedFile]);

        }
    } catch (e) {
        console.error(e)
        throw (e)
    }

}
1 Like

Did you log the result you got from http.getAsync() ?

Yes… this is a print of the console.

And here a print of the file as I opened it on Notepad ++

This is a link for the file I’m running the tests:
Test Document.pdf

And here a link to the full copy of the console log:
ConsoleLog.txt

Please double check the type of the return value from http.getAsync(), so you know exactly what you’re dealing with – e.g. is it a String, ArrayBuffer, etc.

Hi there, I’m back :slightly_smiling_face:

this is how I’ve tested the type.

            const f = await http.getAsync(fileUrl, { 'headers': { 'Authorization': 'Token mytoken' } });

            console.log(['Type: ', Object.prototype.toString.call(f)])
            console.log(['Type: ', typeof f])

and it returns

image

So, it seems the method http.getAsync is designed for text responses only. I suppose this convertion is corrupting the file content.

I’ve also came across with the following issue with this method (it has a limit size in response)

1 Like