If you are new to Google Apps Script or programming in general, Google Apps Script Web Apps may seem daunting. The good news is that it is easy to understand with a little trial and error.
This tutorial will give you 12 recipes to help you get started with the doGet
and doPost
functions and show you how to return HTML, JSON, and plain text. From there, you can go on to customize your Web App to your needs. But first, let’s get the basics out of the way.
What do doGet
and doPost
do?
Since you are starting to build a web app, you should probably know about HTTP. HTTP is the specification for how different machines on the web send and receive information from one another. HTTP allows several types of “requests,” but what we see most often are GET and POST requests. doGet
and doPost
functions define how a Google Apps Script web app scripts handle GET and POST requests from other machines and determines what they return or do.
A simple example of a GET request happens every time you enter a URL into your web browser. The web server at that domain then handles your request and returns an HTML web page. GET requests are the most common type of request on the internet. For our purposes, GET requests are made of up of a domain, e.g., example.com
a path, e.g., /fruits/apples/
and often a query string, e.g.,?variety=fuji&count=4With Google Apps Script, the domain will always be script.google.com, and the path will always look something like /macros/s/AKf...ycb/exec
(or /dev
), and the query string can be whatever you want it to be, in order to specify how the web app dynamically generates the content it returns.
POST requests are similar to GET requests but slightly more powerful. Rather than asking for content, they are used to send data from one machine to another. The most common use of POST requests is web forms, like signup forms and ecommerce checkout pages. POST requests are not limited to sending form text though. They can transfer image, audio, and a number of other types of files. This tutorial will only cover JSON, but if you need more than that, you probably don’t need this tutorial!
Your First Web App “Hello World”
Let’s start with a few easy examples. The next three code snippets serve the same content in three different formats.
To try them out:
- Copy and paste them into a new Google Apps Script.
- Click Publish on the main menu and then Deploy as web app…
- Click “Test web app for your latest code.”
Returning Plain Text
The ContentService.createTextOutput
method is the most basic way to return content from a GET request but is the building block for most other types of content. The TextOutput
objects created by this method returns a response of type, text/plain by default, but can be set to ATOM, CSV, ICAL, JAVASCRIPT, JSON, RSS, TEXT, VCARD, and XML.
function doGet(){ textOutput = ContentService.createTextOutput("Hello World! Welcome to the web app.") return textOutput }
Returning JSON
This is a simple pattern. Just serialize the Javascript object as JSON using JSON.stringify()
, and set the content-type header with the setMimeType()
method. This is important when returning different media types because you don’t want to let the recipient of your request guess the MIME type. For more on this, see my Google Apps script JSON REST API tutorial.
function doGet(){ var appData = { "heading": "Hello World!", "body": "Welcome to the web app." }; var JSONString = JSON.stringify(appData); var JSONOutput = ContentService.createTextOutput(JSONString); JSONOutput.setMimeType(ContentService.MimeType.JSON); return JSONOutput }
Returning HTML
The HTMLService.createHtmlOutput()
method has two purposes: to clean of any security risks before the HTML is returned to the browser and to implicitly set the MIME type to text/html
. To construct web pages, you can assemble the HTML string, as shown below, or you can use templates.
function doGet(){ var HTMLString = "<style> h1,p {font-family: 'Helvitica', 'Arial'}</style>" + "<h1>Hello World!</h1>" + "<p>Welcome to the Web App"; HTMLOutput = HtmlService.createHtmlOutput(HTMLString); return HTMLOutput }
Dynamic Web Pages with the HTML Service
External Content, Query Strings, and HTML Templates
Let’s make this interesting. Google Apps Script can assemble web pages based on dynamic inputs. In the example below, we use an external CSS file and the query string parameters to create dynamic content. The doGet
and doPost
parameter take one default argument (commonly e), which holds information about the request “event.” From that e object, you can pull of information like query string values, as shown below. See the working version of the web app here.
To take this one step further, you can create HTML template files in Google Apps Script and evaluate those templates rather than creating the template in the script. Additionally, you can use information from the Google Drive, Gmail, and other Google APIs to populate your app.
function doGet(e){
// use an externally hosted stylesheet
var style = '<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">';
// get the query "greeting" parameter and set the default to "Hello"
var greeting = e.parameter.greeting || "Hello";
// get the query "name" parameter and set the default to "World!"
var name = e.parameter.name || "World";
// create and use a template
var heading = HtmlService.createTemplate('<h1><?= greeting ?> <?= name ?>!</h1>')
// set the template variables
heading.greeting = greeting;
heading.name = name;
var content = "<p>Welcome to the web app.</p>";
var HTMLOutput = HtmlService.createHtmlOutput();
HTMLOutput.append(style);
HTMLOutput.append(heading.evaluate().getContent());
HTMLOutput.append(content);
return HTMLOutput
}
Google Apps Script doPost
Example
An API Proxy
This example was inspired by my last post about custom Slack slash commands. This doPost
example demonstrates how to handle POST requests, access request query string parameters, make HTTP requests to other services (in this case, the Chuck Norris joke API) with UrlFetchApp
, and break the script into functions.
The reason I made this was because I got data from the Slack app that was formatted as a query string,
&text=Trevor%20Fox
that I needed to use to get data from an API that would be formatted as JSON,
{ "type": "success", "value": { "id": 268, "joke": "Time waits for no man. Unless that man is Chuck Norris." } }
to then send back to Slack app as plain text.
Time waits for no man. Unless that man is Trevor Fox.
This problem also exists if you want to use another service that requires that data be formatted in a specific way- like the IFTTT Maker Channel.
function doPost(e){ // Get the "text" query string value // eg. &text=Your%20Name var name = e.parameter.text // Get the Chuck Norris Joke var chuckQuote = postChuckNorris(name); // Return plain text Output return ContentService.createTextOutput(chuckQuote); } // Make a call to the Chuck Norris joke API // parse the JSON and return only the joke function postChuckNorris(name){ var queryString = makeQueryString(name) var chuckData = UrlFetchApp.fetch("http://api.icndb.com/jokes/random/" + queryString); var chuckJSON = JSON.parse(chuckData.getContentText()); var chuckQuote = chuckJSON.value.joke; return chuckQuote } // Helper function to assemble the query string for // calling the Chuck Norris API from a given name function makeQueryString(name){ var query = "" if (name !== undefined){ var names = name.split(" "); query = "?firstName=" + names[0]; if (names[1] !== undefined){ query += '&lastName=' + names[1]; } } return query }
More than Just Returning Content
Dynamically Create and Save a PDF File to Google Drive
This example is similar to the dynamic HTML example above but instead of making a dynamic web page, it creates and saves a PDF document in Google Drive. This would also work with doPost
in a situation where you would want to send more information to the app when creating you PDF. Check out the live script. *Note, this will create a PDF file in you Google Drive each time you go to the URL.
This takes the functionality of the Google Apps Script web app one step further. This script demonstrates the capability to carry out any task or trigger any other service just from GET’ing or POST’ing to your web app.
function doGet(e){
// get the query "greeting" parameter and set a default to "Hello"
var greeting = e.parameter.greeting || "Hello";
// get the query "name" parameter and set a default to "World!"
var name = e.parameter.name || "World";
// create the PDF
var pdf = makePDF(greeting,name)
// save the PDF to Drive
var driveFile = DriveApp.createFile(pdf).setName("greetings.pdf");
// tell the user how to access it
var fileURL = driveFile.getUrl();
var fileName = driveFile.getName();
var HTMLOutput = HtmlService.createHtmlOutput("<p>Your made a PDF.</p>"
+ "<p> You can download it here: "
+ '<a target="blank" href="' + fileURL + '">' + fileName + '</a></p>');
return HTMLOutput
}
function makePDF(greeting, name){
// use an externally hosted stylesheet
var style = '<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">';
// create and use a template
var heading = HtmlService.createTemplate('<h1><?= greeting ?> <?= name ?>!</h1>')
// set the template variables
heading.greeting = greeting;
heading.name = name;
var content = "<p>Here is your PDF.</p>";
var PDFOutput = HtmlService.createHtmlOutput('<div class="container">');
PDFOutput.append(style);
PDFOutput.append(heading.evaluate().getContent());
PDFOutput.append(content);
PDFOutput.append('</div>');
var blob = Utilities.newBlob(PDFOutput.getContent(), "text/html", "text.html");
var pdf = blob.getAs("application/pdf");
return pdf
}
Publishing and Permissions
When you are ready to launch your new Google Apps Script web app. You should save a version and define who and how users and other machines can access your app. There are a couple important things to note.
If your app offers any capability to interact with other Google Drive services, the app should be set to Execute the App As: User accessing the web app.
If you want to allow other services to interact with your web app (as an API or proxy, the app should be accessible to Execute the App As: Me ([email protected]) and allow Anyone, even anonymous.
I hope this gets you started! In the comments, let me know if you are having any trouble getting your app up and running. Happy hacking!
Hello!
Great information! Thanks a lot for sharing.
I am having problems after I finished publising my web app and restricted access to only accounts in my domain. It was working fine when was published to allow anyone.
Any thoughts?
Hey Victor, I wish I could help but I don’t have any experience with this type of access restriction. Good luck!