2
votes

If I use two forms that are both the same but one has a method of GET and one has a method of POST when I run them one uses the doGet and the other uses the doPost(). But that doesn't happen when I do the same thing with the UrlFetch() command by providing the input from a Prompt.

The html:

The top form is a GET and the bottom form is POST.

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  <h3>GET</h3>
    <form action="https://script.google.com/a/cooper/macros/s/AKfycbzlYgw2cw8q7u9qTxM/exec" enctype="application/x-www-form-urlencoded" method="GET">
      <input type="text" name="one" value="" />
      <br /><input type="text" name="two" value="" />
      <br /><textarea rows="2" cols="25" name="three" placeholder="Enter Text Here"></textarea>
      <br /><input type="submit" value="Submit" />
    </form>
 <h3>POST</h3>   
    <form action="https://script.google.com/a/cooper/macros/s/AKfycbzlYgw2cw8q7u9qTxM/exec" enctype="application/x-www-form-urlencoded" method="POST">
      <input type="text" name="one" value="" />
      <br /><input type="text" name="two" value="" />
      <br /><textarea rows="2" cols="25" name="three" placeholder="Enter Text Here"></textarea>
      <br /><input type="submit" value="Submit" />
    </form>
  </body>
</html>

Code.gs:

function doGet(e){
  Logger.log('doGet: %s',JSON.stringify(e));
  if(e.parameter) {
    var data=e.parameter;
    handleFunction(data,'get');//This hardwires the term get to the ouput
  }
  return HtmlService.createHtmlOutputFromFile('testing');
}

function doPost(e){
  console.log('doPost Entry',JSON.stringify(e));
  if(e.postData.length!=-1) {
    var data=e.parameter;
    handleFunction(data,'post');//This hardwires the term post to the ouput
  }
  return ContentService.createTextOutput('doPost Return:' + JSON.stringify(e.postData.contents));
}

function handleFunction(data,source){
  console.log('handleFunction Entry: %s',JSON.stringify(data));
  var one=data.one;
  var two=data.two;
  var three=data.three;
  var ss=SpreadsheetApp.getActive();
  var sheet=ss.getActiveSheet();
  sheet.appendRow([source,one,two,three]);
}

function postit() {
  // DriveApp.getFiles() //I copied this from a Tanaike example.  I don't know if I need it still
  var ask=SpreadsheetApp.getUi().prompt("Enter first/second/third/method", SpreadsheetApp.getUi().ButtonSet.OK) 
  if(ask.getSelectedButton()==SpreadsheetApp.getUi().Button.OK) {
    var dA=ask.getResponseText().split('/');//Just an easy way to get 4 pieces of data at one time
    if(dA.length==4) {
      var url=ScriptApp.getService().getUrl();
      var data={"one":dA[0],"two":dA[1],"three":dA[2]};
      //the method is provide from the last term of the above prompt
      var options={"method":dA[3],"payload":data,"headers":{"Authorization":"Bearer " + ScriptApp.getOAuthToken()},"muteHttpExceptions": true};
      var resp=UrlFetchApp.fetch(url, options);
      Logger.log('UrlFetch Response: %s',resp);
    }
  }
}

Animation:

enter image description here

This what I ended up with and it runs in Rhino and V8

function postit() {
  // DriveApp.getFiles() 
  var ask=SpreadsheetApp.getUi().prompt("Enter first/second/third/method", SpreadsheetApp.getUi().ButtonSet.OK); 
  if(ask.getSelectedButton()==SpreadsheetApp.getUi().Button.OK) {
    var dA=ask.getResponseText().split('/');
    if(dA.length==4) {  
      if(dA[3]=="POST") {
        var url=ScriptApp.getService().getUrl();
        var data={"one":dA[0],"two":dA[1],"three":dA[2]};
        var options={"method":dA[3],"payload":data,"headers":{"Authorization":"Bearer " + ScriptApp.getOAuthToken()},"muteHttpExceptions": true};
      }else if(dA[3]=="GET") {
        var url=Utilities.formatString('%s?one=%s&two=%s&three=%s',ScriptApp.getService().getUrl(),dA[0],dA[1],dA[2]);
        var data={"one":dA[0],"two":dA[1],"three":dA[2]};
        var options={"method":dA[3],"headers":{"Authorization":"Bearer " + ScriptApp.getOAuthToken()},"muteHttpExceptions": true};
      }
      var resp=UrlFetchApp.fetch(url, options);
    }
  }
}
1
Related: stackoverflow.com/a/56216818 (Not as good as Tanaike's answer, but just linking it to this question) - TheMaster
Thanks that's useful for a more universal solution with an unknown payload. To be honest this is that first time I really got into the guts of UrlFetch. I've been looking at other peoples questions for a while and was picking up a few things here and there but there's nothing doing it yourself to figure what you don't know. - Cooper

1 Answers

1
votes

How about this answer? Please think of this as just one of several possible answers.

Issue and workaround:

I think that the reason of your issue is due to the data is requested with payload for POST and GET methods. At UrlFetchApp, it seems that when the data is used as payload, POST method is used, even when method is GET. In order to send the data as GET method, please add them to the query parameter.

(I thought that when the data is send as payload with the GET method, the data could be sent as GET before. But about this, I only had a faint memory. I apologize for this.)

In order to avoid this, how about the following modification as the simple modification?

Pattern 1:

In this pattern, the query parameter is used for the GET method.

Modified script:

function postit() {
  // DriveApp.getFiles() //I copied this from a Tanaike example.  I don't know if I need it still
  var ask=SpreadsheetApp.getUi().prompt("Enter first/second/third/method", SpreadsheetApp.getUi().ButtonSet.OK) 
  if(ask.getSelectedButton()==SpreadsheetApp.getUi().Button.OK) {
    var dA=ask.getResponseText().split('/');//Just an easy way to get 4 pieces of data at one time
    if(dA.length==4) {
      var url=ScriptApp.getService().getUrl();

      // --- I modified below script.
      var potions = {};
      if (dA[3] == "POST") {
        var data={"one":dA[0],"two":dA[1],"three":dA[2]};
        //the method is provide from the last term of the above prompt
        options={"method":dA[3],"payload":data,"headers":{"Authorization":"Bearer " + ScriptApp.getOAuthToken()},"muteHttpExceptions": true};
      } else if (dA[3] == "GET") {
        options={"method":dA[3],"headers":{"Authorization":"Bearer " + ScriptApp.getOAuthToken()},"muteHttpExceptions": true};
        url += `?one=${dA[0]}&two=${dA[1]}&three=${dA[2]}`;
      }
      // ---

      var resp=UrlFetchApp.fetch(url, options);
      Logger.log('UrlFetch Response: %s',resp);
    }
  }
}

Note:

  • Please enable V8.
  • // DriveApp.getFiles() of the comment line is used for automatically adding the scope of https://www.googleapis.com/auth/drive.readonly with the script editor. This is used for accessing to Web Apps using the access token.

References:

If I misunderstood your issue and this was not the direction you want, I apologize.