8

I'm trying to POST a file to a REST API via Google Apps Script. The idea is that I have a process that is creating copies of a Google Doc, and I want to be able to post those newly created Docs to a third party system.

I found in UrlFetchApp that I can send files. However, I'm having issues sending the correct header values.

My request looks like so:

var file = DriveApp.getFileById(fileId);
var body = {
  "file": file.getAs(MimeType.PDF)
};
var headers = {
  'Content-Disposition': 'attachment; filename="'+ file.getName() +'"',
  'Content-Length': file.getSize()
};

My options when I call UrlFetchApp.fetch(url, options) looks like :

({
  method:"POST", 
  headers:{
      'Content-Disposition':"attachment; filename=\"My Merge Development_row_1.pdf\"", 
      'Content-Length':90665, 
       Authorization:"Bearer TOKEN"
  }, 
  contentType:"application/x-www-form-urlencoded", 
  muteHttpExceptions:true, 
  payload:{file:Blob}
})

The API that I'm sending the files to requires the 'Content-Length' header. But, when I try to set a value for 'Content-Length' header I get an Apps Script error, "Attribute provided with invalid value: Header:Content-Length". If I don't set the Content-Length header then the API responds that the Content-Length and file size don't match.

Any ideas on how I set the Content-Length header so I can POST the file?

stmcallister
  • 1,682
  • 1
  • 12
  • 21

1 Answers1

13

There is an existing ticket highlighting that the documentation is not clear on this very issue

The solution is:

Move content length value from "content-Length" name/value pair in headers to the advanced argument "contentLength"

So in your example your options should look like

({
  method:"POST", 
  headers:{
      'Content-Disposition':"attachment; filename=\"My Merge Development_row_1.pdf\"", 
       Authorization:"Bearer TOKEN"
  }, 
  contentLength: 90665,
  contentType:"application/x-www-form-urlencoded", 
  muteHttpExceptions:true, 
  payload:{file:Blob}
})

EDIT: Added a full example function to get contentLength and blob shown below:

function testFilePost() {
  var file = DriveApp.getFileById(doc_id).getAs(MimeType.PDF);
  var headers = {
    'Content-Disposition': 'attachment; filename="'+ file.getName() +'"',
  };
  var options =
      {
        "method" : "post",
        "payload": file.getBytes(),
        "headers": headers,
        "contentLength": file.getBytes().length,
      };
  var result = JSON.parse(UrlFetchApp.fetch('http://httpbin.org/post', options).getContentText());
  Logger.log(result);
}
mhawksey
  • 2,013
  • 5
  • 23
  • 61
  • Thanks, @mhawksey! I made this change, and starred the issue. The change got me passed the Google Apps Script error, however the API now doesn't see the value being sent. I'm still getting the message that the Content-Length doesn't match the file length. I'm now trying to see what is actually being sent by UrlFetchApp, but I'm not seeing the request when inspecting Network traffic in Google Dev Tools. Is there some place else I can see the POST being sent by UrlFetchApp? – stmcallister Oct 28 '14 at 18:56
  • 1
    Swapping out your service endpoint with httpbin should work (See http://stackoverflow.com/a/9770981/1027723) – mhawksey Oct 28 '14 at 19:16
  • Cool! httpbin is quite helpful! According to my output from httpbin my header value for Content-Length: 60. Although, my options.fileLength = 90665. Any ideas what could cause these two to be different? – stmcallister Oct 28 '14 at 22:01
  • 1
    I've updated my answer to include a sample function which gets the Google Doc as pdf and calcs content-length – mhawksey Oct 29 '14 at 00:32
  • Thank you, @mhawksey! The updated example was awesome. It turns out I also needed to set my Content-Type to 'application/pdf'. Thanks again for your help! – stmcallister Oct 29 '14 at 16:50
  • Cool. Thanks for noting the Content-Type – mhawksey Oct 29 '14 at 21:05