Call API: Send a file with content-type multipart/form-data

Hey Gliders,
I want to create a POST call to an external API including a file with some attributes. The external API only accepts multipart form data.

External API Doc: Upload Document to a Signature Request

Therefore I tried to convert the file to multipart with a small JS script (see below) but in the glide table there’s just a loading symbol (see Screenshot), I cannot use the method output / JS Glide column in the Call API action and the call causes an API error response.

Is Glide supporting API calls with content-type multipart/form-data?
If that is the case how can I properly use that, e.g. how does the request body need to look like?


JavaScript - File to multipart form data conversion:
p1 - file_url
p2 - file_name

const getFormDataFromUrl = async (url, fileName) => {
  try {
    // Fetch the file from the URL
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`Failed to fetch file: ${response.statusText}`);
    }

    // Convert the file to a Blob
    const blob = await response.blob();

    // Create a FormData object
    const formData = new FormData();
    
    // Append the file as a Blob with the specified file name
    formData.append('file', blob, fileName);
    
    // Add additional fields for YouSign's requirements
    formData.append('nature', 'signable_document');
    formData.append('alignment', 'left');
    formData.append('y', '40');
    formData.append('parse_anchors', 'true');

    // Return the FormData object
    return formData;
  } catch (error) {
    console.error("Error creating FormData from URL:", error);
    throw error;
  }
};

return getFormDataFromUrl(p1, p2);

One thing is that you are using an asynchronous call, so you need to await it. That’s what’s causing the spinning wheel.

Second, you are attempting to return an object, which may not work. The javascript column can only pass text strings in and out.

1 Like

@Jeff_Hager Do you know a better way to get this done in Glide somehow?
I am a little bit lost at this point because it’s quite Glide-specific.

Any solution ideas would help me a lot. :slight_smile:

I did that a few weeks ago. Let me find this and I will let you now.

That would be awesome! @MaximeBaker :pray:

1 Like

You want to do the call from the JavaScript code or with the official Call API integration?

Currently I am trying to do it with the Call API integration but I am open for everything that works.

Perfect, I remembered doing it with Call API. Just need to find it. Not on a computer right now, give me an hour.

Thanks a lot! :slight_smile:

1 Like

Let’s get started!

First, you’ll need to set the endpoint of the API you’re calling (no surprises there! :stuck_out_tongue_winking_eye:). Next, ensure the header Content-Type is set to multipart/form-data.

Instead of placing your form data in the request body, you’ll be adding each key-value pair to the query string section. You can add as many key-value pairs as needed.

If you want, you can also specify where to set the response body.

Here’s an example of how it should look:

Don’t mind the key question[options] in my example. That’s just how the API I’m calling expects it. Your API may require something different.

Let’s take a look:
chrome_vph41hG4kA

Give it a try and let me know if you need help!

2 Likes

Thanks a lot @MaximeBaker. That gives me a good understanding where I can put my file in for the request!

Do you also know how that might work with a PDF file stored in Glide Google cloud storage?, i.e. how to convert the PDF file url to Blob in Glide (that’s how the API I am calling expects the file) so that I can put in as Query.value?

Would that work for you ?

async function fetchPdfAsBlob(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) 
      throw new Error('Failed to fetch PDF');
    return await response.blob();
  } catch (error) {
    console.error('Error fetching PDF:', error);
  }
}

const blob = await fetchPdfAsBlob(p1)

function blobToBase64(blob) {
  return new Promise((resolve, _) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.readAsDataURL(blob);
  });
}

return blobToBase64(blob)

1 Like

Wow. Thanks for the efforts! So a pure Blob version of the file isn‘t possible somehow in Glide? … because the API I am calling doesn‘t accept base64.

I am trying to do something for you. Give me a sec. :slight_smile:

1 Like

Thanks a lot Maxime! :slight_smile:

1 Like

I implemented a feature to convert a file URL to binary data for an API call, but I’m seeing some unexpected behaviour in the Call API integration. I’ve opened a ticket to investigate further. Here’s an overview of what I did.

Step 1: Fetching the PDF as a Blob

The first function downloads a PDF file from a URL and returns it as a Blob:

async function fetchPdfAsBlob(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) 
      throw new Error('Failed to fetch PDF');
    return await response.blob();
  } catch (error) {
    console.error('Error fetching PDF:', error);
  }
}

const blob = await fetchPdfAsBlob(p1);

Step 2: Converting the Blob to a Binary String

This next function reads the Blob as a binary string, which can be used in the request body:

function blobToSomething(blob) {
  return new Promise((resolve, _) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.readAsBinaryString(blob);
  });
}

const output = await blobToSomething(blob);
return output;

Purpose: The output now contains the binary representation of the PDF, ready to be inserted into the request body.

Step 3: Building the API Call Request Body

To prepare the request body for the API call, I used the following template:

--XXX
Content-Disposition: form-data; name="file"; filename="test.pdf"
Content-Type: application/pdf

PDF_FILE_DATA
--XXX--
  • Set Content-Type to multipart/form-data; boundary=XXX.
  • Replace PDF_FILE_DATA with the binary data obtained from the blob.

Step 4: Sending the Request via Call API Integration

In testing with Postman, this setup works as expected. However, in the Call API integration, it seems that some unexpected modifications are occurring to the body.


image

2 Likes

Unfortunately it didn’t fully solve it for my API. We solved it by making this API call outside of Glide and calling that one with a JSON request body.

Nevertheless, thanks a lot for your limitless help and support @MaximeBaker.
You’re really an awesome part of the Glide community!:pray:

2 Likes

I appreciate that thanks !!

1 Like