javascriptgoogle-apps-scriptweb-applications

Google Apps Script - missing e.postData and BLOB parameters


Could not find any info on my problem below - so posting.

I am uploading a BLOB to a google-apps-script webapp - code and log below.

  1. e.postData is missing on the webapp doPost(e)
  2. e.parameter.**NewsFile** is missing
  3. the e.contentLength indicates the data is received - checked with 1Mb BLOB
  4. the client side formdata indicates NewsFile is being attached
  5. chrome.devtools show correct payload sent to server

I am using FormData because I need to programatically attach files/blobs to the send request.

Any ideas/insight greatly appreciated.

// client code  
function clientTest() {  
    const content = '<q id="a"><span id="b">hey!</span></q>';  
    const blob = new Blob([content], { type: "text/xml" });  
    const formdata = new FormData();  
    formdata.append("TestKey", "TestValue");  
    formdata.append("NewsFile", blob);  
    console.log(`client send info :: ${[...formdata.keys()].join(" | ")}`);  
    fetch("webappurl", { method: "POST", body: formdata });  
}  

// client log  
// client send info :: TestKey | NewsFile


// server code - google apps script webapp 
function doPost(e) {
    console.info(`e.keys = ${[...Object.keys(e)].join(" | ")}`);
    console.info(`param.keys = ${[...Object.keys(e.parameter)].join(" | ")}`);
    console.info(`post.length = ${e.contentLength}`); 
}    

// server log
// e.keys = parameters | contextPath | parameter | contentLength | queryString | pathInfo  
// param.keys = TestKey  
// post.length = 684

Solution

  • In your client script, you wanted to request multipart/form-data. Unfortunately, in the current stage, Web Apps cannot correctly receive the values of multipart/form-data. In this case, your value is required to be sent as string data. When your showing script is modified, how about the following modification?

    Modified script 1:

    In this modification, it supposes that the data is a string data.

    Javascript:

    function clientTest() {  
      const content = '<q id="a"><span id="b">hey!</span></q>';  
      const obj = { content, "TestKey": "TestValue" };
      fetch("webappurl", { method: "POST", body: JSON.stringify(obj) });  
    }
    

    Google Apps Script:

    In the case of the above Javascript, the values content and TestKey can be retrieved as follows.

    function doPost(e) {
      // DriveApp.createFile("sample.txt", JSON.stringify(e)); // When you use this line, the event object can be seen as a text file.
    
      const obj = JSON.parse(e.postData.contents);
      const { content, TestKey } = obj;
    
      return ContentService.createTextOutput("ok");
    }
    

    Modified script 2:

    In this modification, it supposes that the data is a binary data.

    Javascript:

    function clientTest() {  
      const content = '<q id="a"><span id="b">hey!</span></q>';
      const blob = new Blob([content], { type: "text/xml" });
      const f = new FileReader();
      f.readAsArrayBuffer(blob);
      f.onload = d => {
        const buf = new Int8Array(d.target.result);
        const obj = { content: [...buf], mimeType: "text/xml", "TestKey": "TestValue" };
        fetch("webappurl", { method: "POST", body: JSON.stringify(obj) });
      }
    }
    

    Google Apps Script:

    In the case of the above Javascript, the values content, mimeType and TestKey can be retrieved as follows.

    function doPost(e) {
      // DriveApp.createFile("sample.txt", JSON.stringify(e)); // When you use this line, the event object can be seen as a text file.
    
      const obj = JSON.parse(e.postData.contents);
      const { content, mimeType, TestKey } = obj;
      DriveApp.createFile(Utilities.newBlob(content, mimeType, "sample"));
    
      return ContentService.createTextOutput("ok");
    }
    

    When this script is run, the data is created in the root folder as a file.

    Note:

    References:

    Added:

    From your following reply,

    Ideal would if the e.parameter already contained all the fields

    In this case, how about the following modification?

    Javascript:

    const content = '<q id="a"><span id="b">hey!</span></q>';
    const blob = new Blob([content], { type: "text/xml" });  
    const f = new FileReader();
    f.readAsArrayBuffer(blob);
    f.onload = d => {
      const buf = new Int8Array(d.target.result);
      const obj = { content: JSON.stringify([...buf]), mimeType: "text/xml", "TestKey": "TestValue" };
      const body = new FormData();
      Object.entries(obj).forEach(([k, v]) => body.append(k, v));
      fetch("webappurl", { method: "POST", body });
    }
    

    Google Apps Script:

    function doPost(e) {
      // DriveApp.createFile("sample.txt", JSON.stringify(e)); // When you use this line, the event object can be seen as a text file.
    
      const { content, mimeType, TestKey } = e.parameter; 
      DriveApp.createFile(Utilities.newBlob(JSON.parse(content), mimeType, "sample"));
    
      return ContentService.createTextOutput("ok");
    }