Skip to content Skip to sidebar Skip to footer

How To Send An Error Status Code Like Bad Request (400) From A Google Script?

This is a doPost function inside a Google App that returns a Hello World message. function doPost(e){ return ContentService.createTextOutput('Hello World'); } Now suppose I wa

Solution 1:

Issue and workaround:

Unfortunately, in the current stage, ContentService cannot modify the status code. When I saw the official document of Class ContentService, such method cannot be found. Ref It seems that this is the current specification.

So in your situation, as the current workaround, how about returning the value as JSON data? By this, you can check the value using the key of JSON data. For example, how about the following sample script?

  • When the correct value without the error is returned,

      return ContentService.createTextOutput(JSON.stringify({value: 'value'}));
    
  • When the value with the error is returned,

      return ContentService.createTextOutput(JSON.stringify({error: 'Error message'}));
    
  • When you need .setMimeType(ContentService.MimeType.JSON), please add this.

Note:

  • When I searched about this at the Google issue tracker, I couldn't find it. So how about reporting this as the future request? Ref

Reference:


Solution 2:

Here's another workaround that allows raising errors on the client side for errors on the web app side. For example, a client might need to catch errors such as bad url args sent to the web app (i.e. the OP's question), or catch errors thrown by a method that is called from doGet() or doPost().

As far as I know, when an error is thrown downstream of doGet() or doPost(), a text error message is returned in the response, but the web app request itself succeeds, so there is no error thrown on the client side. As @Tanaike said, there still seems no way for a Google web app dev to throw an HTTP error from the app (like 400 Bad Request or 500 Internal Server Error).

The idea involves returning a function body from the web app, which the client can use to create and run a dynamic function via the Function() constructor (this assumes Javascript is available on the client).

So the web app can be written to:

  • return a function body that will throw an error for bad args, server method errors, etc.
  • return a function body that will return intended JSON when there is no error

This is a bit of a hack, but it unifies error handling on the client side. The client makes the http request, constructs a function using the function body returned in the response, and then runs this function, all in one try{} block. Then both Google-raised http errors and web app downstream errors can be caught in the catch{} block.

Example setup for a Google Apps Script client making a request to a Google web app:

(1) In the web app doGet() or doPost() function:

// this string will be returned by the webapp
var fnBody;

// for bad url args, return a fnBody that will throw an error with an indicative message 
if(!urlArgsOk()) {
  fnBody =  "'use strict'; throw new Error('POST args error');";  
} 
// if url args are ok, call server method
else {
    try {
      // if the method call succeeds, return a fnBody that will return the intended JSON
      var returnObj = myServerMethod(methodArgs);
      fnBody = "'use strict'; return JSON.stringify(" + JSON.stringify(returnObj) + ");";
    }
    catch(serverErr) {
      // if the method call fails, return a fnBody that will throw an error ...
      // ... simple example shown here, but info from serverErr can be included in fnBody
      fnBody =  "'use strict'; throw new Error('server error');";  
    } 
}    

// return fnBody, which can be run via Function() on the client
return ContentService.createTextOutput(fnBody).setMimeType(ContentService.MimeType.TEXT);

(2) On the client side (Google apps script client making a POST request)

// Set the url, payload, and fetch options
var url = "https://script.google.com/_______/exec?arg1=val1&arg2=val2";
var payload = getPayloadString(); // whatever POST payload needs to be sent

var options = {
  'method' : 'POST',
  'contentType': 'application/json',
  'muteHttpExceptions': false, // let Google http exceptions come through
  'payload' : payload,
  'headers': {authorization: "Bearer " + ScriptApp.getOAuthToken()}
};

// Send a request to the web app
try {

  // make the POST request - this throws Google-generated HTTP errors if any
  var response = UrlFetchApp.fetch(url, options);

  // create the dynamic function from the fnBody returned
  var responseFn = new Function(response.getContentText());
  
  // run the function - this returns intended JSON content
  // or throws web app downstream errors if any
  var responseJson = responseFn();

}
catch(err) {
   // handle either source of error
   console.log(err.message);
}

There are potential security risks associated with dynamic code, so I'm not sure how widely applicable this might be. I might use this in an aplication that lives entirely in a private GCP domain, i.e. with the web app restricted to same-domain users and the client app also in the same domain. Some security is also added by the 'use strict' directive, which boxes the dynamic function in by setting its this to undefined (ref). But it's still a good idea to think through the dynamic code implications (ref1, ref2).


Post a Comment for "How To Send An Error Status Code Like Bad Request (400) From A Google Script?"