Home > Enterprise >  Converting a Google Docs file to PDF in Apps Script using Google Drive API
Converting a Google Docs file to PDF in Apps Script using Google Drive API

Time:01-31

I'm trying to convert a Docs file to PDF in GAS, using Drive API.

Based on what I found, basically the steps are:

  1. Get the Docs file
  2. Convert to PDF
  3. Upload to Drive

What I did was use the 'export' function to get the Docs and convert it to PDF, then 'create' function to upload. My code below:

function test(){
  let service = getOAuthService();
  service.reset();

  // Get the Docs file
  let url = encodeURI("https://www.googleapis.com/drive/v3/files/<id of file>/export?mimeType=application/pdf&supportsAllDrives=true");

  let docFile = getGoogleAPI(url);

  var fileName = "my-test-file.pdf";
  var fileContent = docFile.getBlob();

  var fileMetadata = {
    name: fileName,
    parents: ["<id of parent folder>"],
    mimeType: "application/pdf"
  };

  url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true";

  var header = {
    "Authorization": "Bearer "    service.getAccessToken(),
    "Content-Type": "multipart/related; boundary=<BOUNDARY_STRING>"
  };

  var body = "--<BOUNDARY_STRING>\r\n"  
             "Content-Type: application/json; charset=UTF-8\r\n\r\n"  
             JSON.stringify(fileMetadata)   "\r\n"  
             "--<BOUNDARY_STRING>\r\n"  
             "Content-Type: application/pdf\r\n\r\n"  
             fileContent   "\r\n"  
             "--<BOUNDARY_STRING>--";

  let response = UrlFetchApp.fetch(url, {
    method: "post",
    headers: header,
    payload: body,
    muteHttpExceptions: true
  });

  var responseJson = JSON.parse(response.getContentText());

  if (response.getResponseCode() == 200) {
    Logger.log("File uploaded successfully with ID: "   responseJson.id);
  } else {
    Logger.log("Error uploading file: "   responseJson.error.message);
  }
}

However the generate PDF file is either empty or not in the correct PDF format (cannot preview).

I think the first part (getting the Docs file using export) works, but it's the uploading that has the problem. Maybe an incorrect encoding?

Does anyone know where I am wrong on this?

Thanks in advance!

CodePudding user response:

In your script, fileContent is Blob. Unfortunately, Blob cannot be directly used in this request body. I think that this is the reason for your current issue. In this case, how about the following modification?

Pattern 1:

When your request body is modified, please modify it as follows.

From:

"Content-Type: application/pdf\r\n\r\n"  
fileContent   "\r\n"  

To:

"Content-Transfer-Encoding: base64\r\n\r\n"  
Utilities.base64Encode(fileContent.getBytes())   "\r\n"  
  • In your script, you are using text data as the request body. So, I used the above modification.

Pattern 2:

As another pattern, when your fileContent of Blob is directly used in the request body, please modify it as follows.

From:

var header = {
  "Authorization": "Bearer "    service.getAccessToken(),
  "Content-Type": "multipart/related; boundary=<BOUNDARY_STRING>"
};

var body = "--<BOUNDARY_STRING>\r\n"  
           "Content-Type: application/json; charset=UTF-8\r\n\r\n"  
           JSON.stringify(fileMetadata)   "\r\n"  
           "--<BOUNDARY_STRING>\r\n"  
           "Content-Type: application/pdf\r\n\r\n"  
           fileContent   "\r\n"  
           "--<BOUNDARY_STRING>--";

let response = UrlFetchApp.fetch(url, {
  method: "post",
  headers: header,
  payload: body,
  muteHttpExceptions: true
});

To:

let response = UrlFetchApp.fetch(url, {
  payload: {
    metadata: Utilities.newBlob(JSON.stringify(fileMetadata), "application/json"),
    file: fileContent,
  },
  headers: { authorization: "Bearer "   service.getAccessToken() },
  muteHttpExceptions: true
});
  • In this case, the structure of multipart/form-data is automatically created on the internal server side.
  • This modification can obtain the same result as the above one.

Note:

  • In this modification, it supposes that your value of fileContent is the correct blob, and also, it supposes that your access token of "Bearer " service.getAccessToken() can be used for uploading the file to Google Drive. Please be careful about this.

Reference:

  • Related