Skip to content

Instantly share code, notes, and snippets.

@tanaikech
Last active September 11, 2024 15:51
Show Gist options
  • Save tanaikech/d595d30a592979bbf0c692d1193d260c to your computer and use it in GitHub Desktop.
Save tanaikech/d595d30a592979bbf0c692d1193d260c to your computer and use it in GitHub Desktop.
Multipart-POST Request Using Google Apps Script

Multipart-POST Request Using Google Apps Script

April 20, 2019: GAS library for this situation was published. Please check it at https://github.com/tanaikech/FetchApp.

These sample scripts are for requesting multipart post using Google Apps Script.

In most cases, the multipart request is used for uploading files. So I prepared 2 sample situations as follows. For each situation, the request parameters are different.

  1. Upload a file from Google Drive to Slack.
  2. Convert an excel file to Spreadsheet on Google Drive using Drive API v3.

Multipart post is required for these situations.

1. Uploading Files From Google Drive To Slack

Curl Code

In order to use this sample, please retrieve access token for uploading file to Slack.

If curl is used for this situation, the curl code becomes as follows. But this code uploads a file on local PC to Slack. The detail information is here.

curl -X POST -sSL \
     -F token=### access token ### \
     -F channels=### channel ID ### \
     -F filename=### filename on Slack ### \
     -F title=### title on Slack ### \
     -F file=@### filename ### \
     "https://slack.com/api/files.upload"

Google Apps Script

When above curl code is changed to GAS, the script becomes as follows.

function request_slack1() {
  var fileId = "### file ID on Google Drive ###";
  var metadata = {
    token: "### access token ###",
    channels: "### channel ID ###",
    filename: "### filename on Slack ###",
    title: "### title on Slack ###",
  };
  var url = "https://slack.com/api/files.upload";
  var file = DriveApp.getFileById(fileId);
  var boundary = "xxxxxxxxxx";
  var data = "";
  for (var i in metadata) {
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"" + i + "\"; \r\n\r\n" + metadata[i] + "\r\n";
  }
  data += "--" + boundary + "\r\n";
  data += "Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n";
  data += "Content-Type:" + file.getMimeType() + "\r\n\r\n";
  var payload = Utilities.newBlob(data).getBytes()
    .concat(file.getBlob().getBytes())
    .concat(Utilities.newBlob("\r\n--" + boundary + "--").getBytes());
   var options = {
    method : "post",
    contentType : "multipart/form-data; boundary=" + boundary,
    payload : payload,
    muteHttpExceptions: true,
  };
  var res = UrlFetchApp.fetch(url, options).getContentText();

  Logger.log(res);
}

Another Method

For uploading files to slack, following script can be also used.

function request_slack2(){
  var fileId = "### file ID on Google Drive ###";
  var url = "https://slack.com/api/files.upload";
  var payload = {
    token: "### access token ###",
    channels: "### channel ID ###",
    filename: "### filename on Slack ###",
    title: "### title on Slack ###",
    file: DriveApp.getFileById(fileId).getBlob(),
  };
  var options = {
    method: "POST",
    payload: payload,
    muteHttpExceptions : true,
  };
  var res = UrlFetchApp.fetch(url, options).getContentText();

  Logger.log(res)
}

2. Convert Excel files To Spreadsheets On Google Drive Using Drive API v3.

Curl Code

If curl is used for this situation, the curl code becomes as follows. But this code uploads a file on local PC to Google Drive.

curl -X POST -sSL \
     -H "Authorization: Bearer ### access token ###" \
     -F "metadata={ \
                  name : '### uploaded filename on Google Drive ###', \
                  mimeType : 'application/vnd.google-apps.spreadsheet' \
                  };type=application/json;charset=UTF-8" \
     -F "file=@### Excel file ###;type=application/vnd.ms-excel" \
     "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"

Google Apps Script

When above curl code is changed to GAS, the script becomes as follows.

In this sample, please be careful that contentType is multipart/related not multipart/form-data. The detail information is here.

function request_driveapi() {
  var fileId = "### file ID (excel file) on Google Drive ###";
  var metadata = {
    name: "### uploaded filename on Google Drive ###",
    mimeType: "application/vnd.google-apps.spreadsheet"
  };
  var fields = "id,mimeType,name";
  var url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields="
    + encodeURIComponent(fields);
  var file = DriveApp.getFileById(fileId);
  var boundary = "xxxxxxxxxx";
  var data = "--" + boundary + "\r\n";
      data += "Content-Disposition: form-data; name=\"metadata\"\r\n";
      data += "Content-Type: application/json; charset=UTF-8\r\n\r\n";
      data += JSON.stringify(metadata) + "\r\n";
      data += "--" + boundary + "\r\n";
      data += "Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n";
      data += "Content-Type: " + file.getMimeType() + "\r\n\r\n";
  var payload = Utilities.newBlob(data).getBytes()
    .concat(file.getBlob().getBytes())
    .concat(Utilities.newBlob("\r\n--" + boundary + "--").getBytes());
  var options = {
    method : "post",
    contentType : "multipart/related; boundary=" + boundary,
    payload : payload,
    headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()},
    muteHttpExceptions: true,
  };
  var res = UrlFetchApp.fetch(url, options).getContentText();

  Logger.log(res);
}

References

And then, I analyzed logs from curl codes which were shown above.

@VladiCastillo
Copy link

How would you handle a multipart/form-data for uploading gmail attachments to a third party api? I'm trying to upload a gmail email attachment from a gmail add on that i'm creating.

@slalka
Copy link

slalka commented Dec 11, 2018

Thanks!

@jassiepinkman
Copy link

How would you handle a multipart/form-data for uploading gmail attachments to a third party api? I'm trying to upload a gmail email attachment from a gmail add on that i'm creating.

Have you done with this project?

@rushil1999
Copy link

How would you handle a multipart/form-data for uploading gmail attachments to a third party api? I'm trying to upload a gmail email attachment from a gmail add on that i'm creating.

Did you find the solution, even I am implementing similar functionality.???

@Allanfs
Copy link

Allanfs commented Jan 10, 2024

Thanks a lot! I was trying to send an array to the server API and the default implementation does not handle it.

Debugging I saw that UrlFetchApp deal with arrays serializing it as java code.

Used getRequest and added breakpoint to debug req.
var req = UrlFetchApp.getRequest(url, options)


The API expected to receive 1...* elements called complements[], each with its value. So in form-data should have at least one part with this name.

 ----------------------------abc
Content-Disposition: form-data; name="complements[]"
{"id":0,"name":"Foo" }
----------------------------abc
Content-Disposition: form-data; name="complements[]"
{"id":1,"name":"Bar" }

@tanaikech
Copy link
Author

@Allanfs Thank you for your comment. It seems that the structure of the request body is required to be constructed for every specification of the server side.

@philipsimonhall
Copy link

Just wanted to say thanks for this, I have spent a few weeks going round in circles trying to find a solution that would both support multiple elements in an array and binary files, e.g. pdfs, I could get one, or other to work, but not both.

The breakthrough was your suggestion to put the whole payload into a bytes array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment