Saturday, April 14, 2012

Return From Apps Script Service

A script written in Google Apps Script can be hosted on a Google Sites website and published as service. The service may be accessed anywhere on the web.

Very promising, but if you do not already know, before you get too excited,
a published script is a service which may only return and get:

1. Nothing or null

The script completed but did not return anything.

2. Any object but not UiApp

The script completed but the returned value is not a supported return type.

3. UiApp instance

A nice busy loading spinner and a page full of Javascript which will eventually run and show the UI you constructed in Apps Script.

As you can see, the third option, the only officially documented return type, is what you are expected to do, but unlikely is exactly what you had in mind for a service.

In a multi-tier business environment, the last thing one would associate with a user interface is service - literally.

If you are required to integrate with other services of your own or a third party, exposing services as HTML and scripts is certainly not very desirable.

If you wish to return your own object, the right approach probably would be to file a feature request and wait...

Or if you can't wait and still love Apps Script, here is what you can do.

You may know that Apps Script does not support a user-defined exception or at least not the expected way. If you throw one, you will get something similar to the following:

Syntax error: ... line: ? (line xx)

this time however in HTML text proper - no Javascript.

So the obvious solution is to throw a custom object e.g. JSON, and assume the other party will catch it.

function sendJson(e) {
throw '<![CDATA[' + JSON.stringify(e) + ']]';
}

Calling the service will get for example:

Syntax error: <![CDATA[{"email":'liqiang@example.com'}]]> line: ? (line xx)

if {"email":"liqiang@example.com"} is thrown.

It is trivial to just extract, decode, and parse the content to get the JSON back.

function getJson(s) {
JSON.parse( s.substring(s.indexOf('[CDATA[') + 7, s.lastIndexOf(']]')) );
}


From tests, big objects could be passed, size would not be an issue.

If someday, Google decides to support proper user-defined exception, by contract, your code should still work.

Sample Code