• Stars
    star
    201
  • Rank 194,491 (Top 4 %)
  • Language
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

This is a report to take advantage of Web Apps with Google Apps Script (GAS).

Taking advantage of Web Apps with Google Apps Script

MIT License

Table of contents

Overview

This is a report to take advantage of Web Apps with Google Apps Script (GAS).

Description

There is "Web Apps" as one of the applications using Google Apps Script (GAS). I sometimes use this Web app. But I have only a little information for the specification of Web Apps. So in order to take more advantage of Web Apps, I investigated and summarized this. The aim of this report is to become one of the basic information for creating various applications using Web Apps with GAS.

Deploy Web Apps

When Web Apps is deployed, you can see the following window.

New IDE for Google Apps Script has finally been released at December 7, 2020. Ref For new IDE, please open a dialog by "Deploy" -> "New deployment". And, please select "Web app" at "Select type. By this, you can see the following dialog.

On the other hand, when you use old IDE, you can see the following dialog.

For setting, generally, the following flow is used.

  • On script editor

  • Publish -> Deploy as web app...

    • Project version:
      • "New" and input the description.
    • Pattern 1: Execute the app as: (old IDE), Execute as: (new IDE)
      • Me (old IDE and new IDE)
        • Who has access to the app:
          • Only myself (old IDE and new IDE)
          • Anyone (old IDE), Anyone with Google account (new IDE)
          • Anyone, even anonymous (old IDE), Anyone (new IDE)
    • Pattern 2: Execute the app as: (old IDE), Execute as: (new IDE)
      • User accessing the web app (old IDE and new IDE)
        • Who has access to the app: (old IDE), Who has access (new IDE)
          • Only myself (old IDE and new IDE)
          • Anyone (old IDE), Anyone with Google account (new IDE)
    • Click Deploy.
  • There are Me and User accessing the web app for "Execute the app as:" and Only myself, Anyone and Anyone, even anonymous for "Who has access to the app:" as the options. When Me and User accessing the web app are selected for "Execute the app as:", each "Who has access to the app:" has 3 and 2 options, respectively. From above flow, It is found that there are 5 situations for deploying Web Apps. For each situation, there are 2 methods of GET and POST.

  • At new IDE,

    • Execute the app as: became Execute as. And the values are Me and User accessing the web app. These are the same with the old IDE.

    • Who has access to the app: became Who has access. About the values, please check the following list.

      • When Execute as is Me, the values of Who has access are Only myself, Anyone with Google account and Anyone. In this case, the values of Only myself, Anyone with Google account and Anyone of new IDE are the same with Only myself, Anyone and Anyone, even anonymous, respectively.
      • When Execute as is User accessing the web app, the values of Who has access are Only myself and Anyone with Google account. These are the same with Only myself and Anyone of the old IDE, respectively.

In this report, I would like to introduce about the specification for Web Apps deployed by 5 situations.

Redeploying Web Apps without Changing URL of Web Apps for new IDE

At March 15, 2021, one endpoint is created for one deployment. Ref By this, when you redeploy "Web Apps", the endpoint is changed. Because the deployment ID is changed. It seems that this it the new specification. In this report, I would like to introduce the method for redeploying Web Apps without changing the URL of Web Apps for new IDE.

The detail document can be seen at https://gist.github.com/tanaikech/ebf92d8f427d02d53989d6c3464a9c43.

5 situations for Web Apps

  1. Situation 1
    • "Execute the app as:" : Me
    • "Who has access to the app:": Only myself
  2. Situation 2
    • "Execute the app as:" : Me
    • "Who has access to the app:": Anyone
  3. Situation 3
    • "Execute the app as:" : Me
    • "Who has access to the app:": Anyone, even anonymous
  4. Situation 4
    • "Execute the app as:" : User accessing the web app
    • "Who has access to the app:": Only myself
  5. Situation 5
    • "Execute the app as:" : User accessing the web app
    • "Who has access to the app:": Anyone

How to access to Web Apps

There are 5 situations for the deployed Web Apps, as mentioned above. And the methods for accessing to the deployed Web Apps are divided into 2 types. Those are the method which accesses using browser and the method which accesses using Curl, Google Apps Script and so on which don't use browser. Each method is used by the owner of Web Apps and the client users. The flow which summarized them is as follows.

1. Owner accesses to Web Apps using browser

  • For Situation 1, 4
    • Owner can access and run the script of Web Apps by the login to Google.
  • For Situation 2, 5
    • Owner can access and run the script of Web Apps by the login to Google.
  • For Situation 3
    • Owner can access and run the script of Web Apps without the login to Google.

2. Client users access to Web Apps using browser

  • For Situation 1, 4
    • Client users cannot access and run the script of Web Apps.
  • For Situation 2, 5
    • Client users can access and run the script of Web Apps by the login to Google.
  • For Situation 3
    • Client users can access and run the script of Web Apps without the login to Google.

3. Owner accesses to Web Apps using Curl, Google Apps Script and so on which don't use browser

  • For Situation 1, 4
    • Owner can access and run the script of Web Apps by using the access token.
  • For Situation 2, 5
    • Owner can access and run the script of Web Apps by using the access token.
  • For Situation 3
    • If the script of Web Apps uses some scopes, owner has to authorize the scopes by own browser.
    • Owner can access and run the script of Web Apps without the login to Google.

4. Client users access to Web Apps using Curl, Google Apps Script and so on which don't use browser

  • For Situation 1, 4
    • Client users cannot access and run the script of Web Apps.
  • For Situation 2, 5
    • At first, the project that Web Apps was deployed has to be shared with client users who use Web Apps.
      • I confirmed that from April 11, 2018, it is required to be shared the project to access to Web Apps. This might be due to the update of Google.
    • If the script of Web Apps uses some scopes, client users have to authorize the scopes by own browser.
    • Client users can access and run the script of Web Apps without the login to Google.
  • For Situation 3
    • If the script of Web Apps uses some scopes, client users have to authorize the scopes by own browser.
    • Client users can access and run the script of Web Apps without the login to Google.

Required parameters for accessing to deployed Web Apps

The simple explanations for above 5 situations were summarized as the following table. Owner and client users mean the owner who deployed Web Apps and the users who use the deployed Web Apps, respectively.

Situations Script of Web Apps Authorization for scopes Owner Client users Share project
Situation 1 Run as owner. Only owner Access with access token. Cannot access. No
Situation 2 Run as owner. Only owner Access with access token. Access with access token. Yes
Situation 3 Run as owner. Only owner Access without access token. Access without access token. No
Situation 4 Run as each user. Each user Access with access token. Cannot access. No
Situation 5 Run as each user. Each user Access with access token. Access with access token. Yes

For example, at situation 5, the script of Web Apps is run as each user (owner and client users). The authorization for the scopes of scripts of Web Apps is required to run the scripts. This authorization has to be done by each user (owner and client users) using own browser. The access token is required for each user (owner and client users) to access to Web Apps. In order to access to Web Apps from client users, the project deployed Web Apps has to be shared with the users.

Authorization for scopes

  • When Web Apps is deployed as "Execute the app as:" : Me by owner, the authorization screen is automatically opened. When the owner authorizes it, owner and client users can run the scripts of Web Apps as the owner.

    • For example, in this situation, when Session.getEffectiveUser().getEmail() is run in this situation by the client users, the retrieved email is the owner's email. From this, it is found that the script is run as the owner.

    • For example, in this situation, when DriveApp.createFile(blob) is run at the script of Web Apps, the file is created in the owner's Google Drive.

  • When Web Apps is deployed as "Execute the app as:" : User accessing the web app by owner, the authorization screen is NOT opened automatically. So before owner and client users access to Web Apps, they have to manually authorize to use the scopes by own browser.

    • If some scopes are used for the scripts of Web Apps, owner and client users have to authorize them only one time using own browser, before it accesses to Web Apps.

      • The URL for authorizing is https://script.google.com/macros/s/#####/exec which is the same to URL of Web Apps. When owner and client users access to the URL using own browser, the following authorization screen is displayed.

      • When you see above screen, please click "REVIEW PERMISSIONS". And select account and authorize to use the scopes. After owner and client users authorized the scopes, they can run the script of Web Apps.

    • For example, in this situation, when Session.getEffectiveUser().getEmail() is run in this situation by the client users, the retrieved email is the each user's email. From this, it is found that the script is run as each user.

    • For example, in this situation, when DriveApp.createFile(blob) is run at the script of Web Apps, the file is created in the each user's Google Drive.

Access token for accessing to Web Apps

  • When Web Apps is deployed as "Who has access to the app:": Only myself or "Who has access to the app:": Anyone by owner, the owner and client users have to access and run the script of Web Apps with own access token.

    • At least, one of scopes for using Drive API is required to be included in the access token. For example, those are

      • https://www.googleapis.com/auth/drive.readonly
      • https://www.googleapis.com/auth/drive.files
      • https://www.googleapis.com/auth/drive
    • Even if the server script uses the scopes except for scripts to use Drive API, the scopes except for scopes for Drive API are not required to be included. Because the use of other scopes is authorized by the browser, before it accesses to Web Apps. This means that when it accesses to Web Apps by GET or POST request, only the scopes for using Drive API are required.

    • For example, when you want to access to Web Apps using GAS, even if you use {"Authorization": "Bearer " + ScriptApp.getOAuthToken()} to the headers, when the error of <TITLE>Unauthorized</TITLE> occurs, please confirm the scopes of the scripts at the script editor. If https://www.googleapis.com/auth/drive is not included in the scopes, please add it. In order to add it, for example, you can put // DriveApp.getFiles() in the scripts as a comment. By this, the script editor will automatically include https://www.googleapis.com/auth/drive.

  • If no scopes are used for the scripts of Web Apps, owner and client users can run the script of Web Apps without the authorization of scopes using own browser. But the access token is required to access to Web Apps, if it is "Who has access to the app:": Only myself or "Who has access to the app:": Anyone.

  • Only when it is "Who has access to the app:": Anyone, even anonymous, owner and client users can access to Web Apps without the access token.

Share project of Web Apps with client users

When client users access to Web Apps with Situation 2 and 5, the owner of Web Apps is required to share the project deployed Web Apps with the client users. If the project is not shared, the error message of <title>Google Drive - Access Denied</title> is returned. For example, if the project is the container-bound script with Spreadsheet, please share the spreadsheet with the client users.

For sharing the project, you can manually share it and use "VIEW" to the permissions.

Also you can share the project using GAS scripts. The sample GAS script for sharing the project with the client users is as follows. When you use this, please input email and fileId. For example, if the project is the container-bound script with Spreadsheet, the fileId is that of spreadsheet. If you want to send a notification email when the project is shared, please modify from sendNotificationEmail=false to sendNotificationEmail=true.

// DriveApp.getFiles() // This comment is used for including a scope of https://www.googleapis.com/auth/drive. Of course, you can use Manifests for the project.
var email = "### Client user's email address ###";
var fileId = "### fileId of project ###";

var url =
  "https://www.googleapis.com/drive/v3/files/" +
  fileId +
  "/permissions?sendNotificationEmail=false";
var params = {
  method: "post",
  headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
  contentType: "application/json",
  payload: JSON.stringify({
    role: "reader",
    type: "user",
    emailAddress: email,
  }),
  muteHttpExceptions: true,
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res);

How to use dev mode from outside

When you deploy Web Apps, you can see the link labeled latest code. The link is like https://script.google.com/macros/s/###/dev. The official document of Google is as follows.

This URL can only be accessed by users who have edit access to the script. This instance of the app always runs the most recently saved code — not necessarily a formal version — and is intended for quick testing during development.

When you access to the link of latest code using your browser under you login to Google, you can access to Web Apps with the dev mode. But if you want to access to Web Apps with the dev mode from outside, there are no documents for the method. Here, it introduces such method.

When it accesses to the URL of latest code from outside, the login screen is returned. This situation indicates that it is required to use the access token for accessing to the URL. So as a sample, I show you the sample curl command as follows. The requirement scope is https://www.googleapis.com/auth/drive.

Requesting to doGet()

curl -L \
  -H "Authorization: Bearer ### access token ###" \
  "https://script.google.com/macros/s/#####/dev"

Also from Standard Query Parameters, you can use the following method using the access token as the query parameter.

curl -L "https://script.google.com/macros/s/#####/dev?access_token=### access token ###"
  • Replace ### access token ### to the value retrieved by ScriptApp.getOAuthToken().
  • Replace https://script.google.com/macros/s/#####/dev to your endpoint retrieved by deploying Web Apps.

Requesting to doPost()

curl -L \
  -H "Authorization: Bearer ### access token ###" \
  -d "key=value" \
  "https://script.google.com/macros/s/#####/dev"

Also from Standard Query Parameters, you can use the following method using the access token as the query parameter.

curl -L \
  -d "key=value" \
  "https://script.google.com/macros/s/#####/dev?access_token=### access token ###"
  • Replace ### access token ### to the value retrieved by ScriptApp.getOAuthToken().
  • Replace https://script.google.com/macros/s/#####/dev to your endpoint retrieved by deploying Web Apps.
  • I used -d "key=value" for the post method. If you don't want to put the values, please replace to -d "".

Note

  • By using above method, you can use the latest script of Web Apps from outside.
  • If you want to use the dev mode as simple test, there is a simple method for retrieving the access token.
    1. Login to Google and open the script editor.
    2. Copy and paste the following script.
      • function getAccesstoken() {Logger.log(ScriptApp.getOAuthToken())} // DriveApp.getFiles()
    3. Run the function getAccesstoken() and retrieve the access token.

By this, you can test it using the retrieved access token.

Event object of Web Apps

When Web Apps is used, doGet(e) and doPost(e) are used for the GET and POST method, respectively. Here, it introduces the event object of e.

Sample script of Web Apps

The sample script for GET and POST method of Web Apps is as follows.

function doGet(e) {
  e.method = "GET";
  return ContentService.createTextOutput(JSON.stringify(e)).setMimeType(
    ContentService.MimeType.JSON
  );
}

function doPost(e) {
  e.method = "POST";
  return ContentService.createTextOutput(JSON.stringify(e)).setMimeType(
    ContentService.MimeType.JSON
  );
}

Sample client for accessing to Web Apps.

As a sample client, curl is used.

Pattern 1

Sample curl

$ curl -L "https://script.google.com/macros/s/#####/exec?key1=value1&key2=value2&key3=value3"

Result

{
  "parameter": {
    "key1": "value1",
    "key2": "value2",
    "key3": "value3"
  },
  "contextPath": "",
  "contentLength": -1,
  "queryString": "key1=value1&key2=value2&key3=value3",
  "parameters": {
    "key1": ["value1"],
    "key2": ["value2"],
    "key3": ["value3"]
  },
  "method": "GET"
}

Pattern 2

Sample curl

$ curl -L -d "key1=value1" -d "key2=value2" "https://script.google.com/macros/s/#####/exec?key3=value3"

Result

{
  "parameter": {
    "key1": "value1",
    "key2": "value2",
    "key3": "value3"
  },
  "contextPath": "",
  "contentLength": 23,
  "queryString": "key3=value3",
  "parameters": {
    "key1": ["value1"],
    "key2": ["value2"],
    "key3": ["value3"]
  },
  "postData": {
    "type": "application/x-www-form-urlencoded",
    "length": 23,
    "contents": "key1=value1&key2=value2",
    "name": "postData"
  },
  "method": "POST"
}

Pattern 3

Sample curl

$ curl -L -d '{"key1": "value1", "key2": "value2"}' "https://script.google.com/macros/s/#####/exec?key3=value3"

Result

{
  "parameter": {
    "key3": "value3",
    "{\"key1\": \"value1\", \"key2\": \"value2\"}": ""
  },
  "contextPath": "",
  "contentLength": 36,
  "queryString": "key3=value3",
  "parameters": {
    "key3": ["value3"],
    "{\"key1\": \"value1\", \"key2\": \"value2\"}": [""]
  },
  "postData": {
    "type": "application/x-www-form-urlencoded",
    "length": 36,
    "contents": "{\"key1\": \"value1\", \"key2\": \"value2\"}",
    "name": "postData"
  },
  "method": "POST"
}

Pattern 4

Sample curl

$ curl -L -H "Content-Type: application/json" -d '{"key1": "value1", "key2": "value2"}' "https://script.google.com/macros/s/#####/exec?key3=value3"

Result

Although the JSON object is sent as application/json and Web Apps recognizes the data as application/json, the JSON parse of contents is not parsed. Please be careful this. In this case, it is required to parse using JSON.parse().

{
  "parameter": {
    "key3": "value3"
  },
  "contextPath": "",
  "contentLength": 36,
  "queryString": "key3=value3",
  "parameters": {
    "key3": ["value3"]
  },
  "postData": {
    "type": "application/json",
    "length": 36,
    "contents": "{\"key1\": \"value1\", \"key2\": \"value2\"}",
    "name": "postData"
  },
  "method": "POST"
}

Pattern 5

Sample curl

In this pattern, the filename is added to the URL as follows.

https://script.google.com/macros/s/#####/exec/fileName.txt

In this case, the authorization is required. Please be careful this. So when the curl command is used, the access token is required to be used as follows.

$ curl -L \
  -H "Authorization: Bearer ###"  \
  -H "Content-Type: application/json" \
  -d '{"key1": "value1", "key2": "value2"}' \
  "https://script.google.com/macros/s/#####/exec/fileName.txt?key3=value3""

Also, when you have already logged in Google account, you can directly access to the URL. But in this case, it is the GET method.

When you run above curl command, you can retrieve the following values. fileName.txt can be retrieved by pathInfo.

Result

{
  "pathInfo": "fileName.txt",
  "contextPath": "",
  "postData": {
    "contents": "{\"key1\": \"value1\", \"key2\": \"value2\"}",
    "length": 36,
    "name": "postData",
    "type": "application/json"
  },
  "contentLength": 36,
  "parameter": {
    "key3": "value3"
  },
  "parameters": {
    "key3": ["value3"]
  },
  "queryString": "key3=value3",
  "method": "POST"
}

pathInfo: Updated on February 14, 2023

In the current stage, it seems that pathInfo can be used with the access token. It supposes that the following sample script is used.

function doGet(e) {
  return ContentService.createTextOutput(JSON.stringify(e));
}

When you log in to your Google account and you access https://script.google.com/macros/s/###/exec/sample.txt with your browser, {"contextPath":"","parameter":{},"pathInfo":"sample.txt","contentLength":-1,"parameters":{},"queryString":""} can be seen.

In this case, when you access it without logging in Google account, even when Web Apps is deployed as Execute as: Me and Who has access to the app: Anyone, the log in screen is opened. Please be careful about this.

And, if you want to access with https://script.google.com/macros/s/###/exec/sample.txt using a script, please request it by including the access token. The sample curl command is as follows. In this case, the access token can be used as the query parameter. Please include one of the scopes of Drive API in the access token.

curl -L "https://script.google.com/macros/s/###/exec/sample.txt?access_token=###"

By this, the following result is returned.

{"contextPath":"","queryString":"access_token=###"},"pathInfo":"sample.txt","parameters":{"access_token":["###"]},"contentLength":-1}

Logs in Web Apps for Google Apps Script

Gists

This is a report for retrieving the logs in Web Apps for Google Apps Script, when it requests to the Web Apps.

Experimental condition

1. Sample script for Web Apps

const doGet = (e) => {
  Logger.log(`GET method: ${JSON.stringify(e)}`);
  console.log(`GET method: ${JSON.stringify(e)}`);
  return ContentService.createTextOutput(
    JSON.stringify({ method: "GET", e: e })
  );
};
const doPost = (e) => {
  Logger.log(`POST method: ${JSON.stringify(e)}`);
  console.log(`POST method: ${JSON.stringify(e)}`);
  return ContentService.createTextOutput(
    JSON.stringify({ method: "POST", e: e })
  );
};
  • This Web Apps is deployed as Execute the app as: Me and Who has access to the app: Anyone, even anonymous.

2. Sample Google Apps Script project

  1. Google Apps Script of standalone type WITHOUT linking Google Cloud Platform (GCP) Project

    • In this case, you can retrieve this standalone Google Apps Script by directly creating.
  2. Google Apps Script of standalone type WITH linking Google Cloud Platform (GCP) Project

    • In this case, you can retrieve this standalone Google Apps Script by this flow.

3. Experimental procedure

To above Web Apps of doGet and doPost, it requests with the following 4 patterns.

  1. For doGet.

    $ curl -L "https://script.google.com/macros/s/###/exec"
  2. For doPost.

    $ curl -L -d "key=value" "https://script.google.com/macros/s/###/exec"
  3. For doGet. Access token is used.

    $ curl -L -H "Authorization: Bearer ###" "https://script.google.com/macros/s/###/exec"
  4. For doPost. Access token is used.

    $ curl -L -H "Authorization: Bearer ###" -d "key=value" "https://script.google.com/macros/s/###/exec"

Result and discussions

The conditions which can confirm the logs are as follows.



Without access token With access token
Without linking GCP Apps Script Dashboard
With linking GCP Stackdriver Apps Script Dashboard and Stackdriver


From above results, it was found as follows.

  • If you use the default Google Apps Script project without linking GCP, in order to retrieve the logs which requested to the Web Apps, please access to the Web Apps using the access token, even when the Web Apps is deployed as Execute the app as: Me and Who has access to the app: Anyone, even anonymous.

  • If you use the Google Apps Script project with linking GCP, you can retrieve all logs of users who accessed to the Web Apps at Stackdriver, even when the Web Apps is deployed as Execute the app as: Me and Who has access to the app: Anyone, even anonymous.

  • In this case, the logs couldn't be seen with Logger.log for above all situations.

IMPORTANT

In the current stage, when the access token is used for XMLHttpRequest and fetch of Javascript in the request headers, the error related to CORS occurs. So, in this report, I would like to propose the workaround for resolving this issue.

Limitation of simultaneous connection to Web Apps

The limitation of simultaneous connection is also investigated. The fetchAll method added by recent Google's update was used for this investigation. I have reported that the fetchAll method is worked by the asynchronous processing. This can be used for measuring the limitation of simultaneous connection. From the result of measurement, it was found that the limitation of simultaneous connection to one Web Apps server is under 30. This is the same with scripts.run method of Apps Script API.

When "Current limitations" of "Quotas for Google Services", it says that the simultaneous executions is 30.

Error messages

When the error messages are returned from Web Apps, you can see the messages into the tag of <title>### Error message ###</title> including in HTML output. From the error messages, you can know the reason of the error using the following table. I think that there may be other errors. So if you found them, when you tell me them, I'm glad.

Execute the app as Who has access to the app Access Status code Error messages Reason
User accessing the web app Only myself,
Anyone
Owner,
Users
200 Authorization needed Scopes for scripts of Web Apps are not authorized.
User accessing the web app,
Me
Only myself,
Anyone
Owner,
Users
200 Meet Google Drive – One place for all your files No access token.
For all settings For all settings Owner,
Users
200 Error "Service invoked too many times in a short time: exec qps. Try Utilities.sleep(1000) between calls." is shown in Body.
User accessing the web app,
Me
Only myself,
Anyone
Owner,
Users
401 Unauthorized Bad access token.
No required scopes.
User accessing the web app,
Me
Anyone Users 403 Google Drive - Access Denied Project of Web Apps is not shared with users.
User accessing the web app,
Me
Only myself Users 404 Google Drive -- Page Not Found Users cannot access.

CORS in Web Apps

In this section, I would like to introduce CORS in Web Apps. As a sample situation, it supposes that Web Apps is requested using GET and POST method with Javascript. The settings of Web Apps are Execute the app as: Me and Who has access to the app: Anyone, even anonymous.

The Javascript of the client side, which was used for testing, is as follows.

const url = "https://script.google.com/macros/s/###/exec";

function get() {
  fetch(url)
    .then((res) => {
      console.log(res.status);
      return res.text();
    })
    .then((res) => console.log(res));
}

function post() {
  const obj = { key: "value" };
  fetch(url, { method: "POST", body: JSON.stringify(obj) })
    .then((res) => {
      console.log(res.status);
      return res.text();
    })
    .then((res) => console.log(res));
}

Sample script 1

Script for Web Apps

const doGet = (e) => {};
const doPost = (e) => {};

Result

For both requests, the following response is returned. Error related to CORS occurs.

Access to fetch at 'https://script.google.com/macros/s/###/exec' from origin 'https://###script.googleusercontent.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Sample script 2

Script for Web Apps

const doGet = (e) => HtmlService.createHtmlOutput();
const doPost = (e) => HtmlService.createHtmlOutput();

Result

For both requests, the following response is returned. Error related to CORS occurs.

Access to fetch at 'https://script.google.com/macros/s/###/exec' from origin 'https://###script.googleusercontent.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Sample script 3

Script for Web Apps

const doGet = (e) => ContentService.createTextOutput();
const doPost = (e) => ContentService.createTextOutput();

Result

For both requests, the following response is returned. No error occurs.

200

Sample script 4

Script for Web Apps

const doGet = (e) => ContentService.createTextOutput();
const doPost = (e) => ContentService.createTextOutput();

Script for Javascript

In this case, axios is used. This sample referred Stackoverflow.

const url = "https://script.google.com/macros/s/###/exec";

async function get() {
  const res = await axios.get(url);
  console.log(res);
}

async function post() {
  const obj = { key: "value" };
  const res = await axios.post(url, obj);
  console.log(res);
}

In this case, at post(), the object is not converted to the string with JSON.stringify.

Result

  • No error occurs at get().
  • Error related to CORS occurs at post().

Removing this error

Please convert the object to the string with JSON.stringify. By this, the error can be removed. No error occurs.

async function post() {
  const obj = { key: "value" };
  const res = await axios.post(url, JSON.stringify(obj));
  console.log(res);
}

When above script didn't work, please set "Content-Type": "text/plain" to the header and test it again. On the other hand, when the following script is used, No error occurs at post().

function post() {
  const obj = { key: "value" };
  fetch(url, { method: "POST", body: obj })
    .then((res) => {
      console.log(res.status);
      return res.text();
    })
    .then((res) => console.log(res));
}

Summary

As the result, in order to prevent the error related to CORS, it was found the following important points.

  1. It is required to return ContentService.createTextOutput() and ContentService.createTextOutput("done") from doGet and doPost.

  2. For POST method, the data is required to be converted to the string and sent to Web Apps.

Reference

Confidentiality of scripts for Web Apps

  • If you don't want to publish the scripts of Web Apps, you can achieve it using Situation 3.

    • In this case, anybody can access the Web Apps.
  • If you want to make only the special users access to Web Apps, you can achieve it using Situation 2 and 5.

    • In this case, the scripts of Web Apps can be seen by the users, because the project of scripts has to be shared with the users.

Sample script of server side

The simple sample-script of server side (Web Apps) is as follows. When the client users access to this server, the server returns URL query and the request body which were sent by the client. And also a text file is created. In this script, the scope of https://www.googleapis.com/auth/drive is used for creating a text file. So when you use this script at Situation 4 and Situation 5 as mentioned above, at first, please authorize the scope by accessing to Web Apps using your browser. After the authorization was done, the text file is created by requesting the following scripts for the client side.

function feedback(e, method) {
  var id = "";
  var user = Session.getEffectiveUser().getEmail();
  if (e.parameter.key1 == "value1") {
    id = DriveApp.createFile(
      "sample.txt",
      "Created by " + user,
      MimeType.PLAIN_TEXT
    ).getId();
  }
  return ContentService.createTextOutput(
    JSON.stringify({
      result: Object.keys(e.parameters).map(function (f) {
        return f + "," + e.parameters[f];
      }),
      method: method,
      createdFile: id ? id + " was created by " + user : "Not created.",
    })
  ).setMimeType(ContentService.MimeType.JSON);
}

function doGet() {
  return feedback(e, "GET");
}

function doPost() {
  return feedback(e, "POST");
}

Sample scripts of client side

Access with access token

GET

Curl

curl -GL \
  -H "Authorization: Bearer ### your access token ###" \
  -d "key1=value1" \
  -d "key2=value2" \
  "https://script.google.com/macros/s/#####/exec?key3=value3"

Google Apps Script

// DriveApp.getFiles() // This comment is used for including a scope of https://www.googleapis.com/auth/drive.
var params = {
  method: "GET",
  headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
  muteHttpExceptions: true,
};
var url =
  "https://script.google.com/macros/s/#####/exec?key1=value1&key2=value2&key3=value3";
var res = UrlFetchApp.fetch(url, params);
Logger.log(res);

POST

Curl

curl -L \
  -H "Authorization: Bearer ### your access token ###" \
  -d "key1=value1" \
  -d "key2=value2" \
  "https://script.google.com/macros/s/#####/exec?key3=value3"

Google Apps Script

// DriveApp.getFiles() // This comment is used for including a scope of https://www.googleapis.com/auth/drive.
var params = {
  method: "POST",
  headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
  payload: { key1: "value1", key2: "value2" },
  muteHttpExceptions: true,
};
var url = "https://script.google.com/macros/s/#####/exec?key3=value3";
var res = UrlFetchApp.fetch(url, params);
Logger.log(res);

Access without access token

GET

Curl

curl -GL \
  -d "key1=value1" \
  -d "key2=value2" \
  "https://script.google.com/macros/s/#####/exec?key3=value3"

Google Apps Script

var params = {
  method: "GET",
  muteHttpExceptions: true,
};
var url =
  "https://script.google.com/macros/s/#####/exec?key1=value1&key2=value2&key3=value3";
var res = UrlFetchApp.fetch(url, params);
Logger.log(res);

POST

Curl

curl -L \
  -d "key1=value1" \
  -d "key2=value2" \
  "https://script.google.com/macros/s/#####/exec?key3=value3"

Google Apps Script

var params = {
  method: "POST",
  payload: { key1: "value1", key2: "value2" },
  muteHttpExceptions: true,
};
var url = "https://script.google.com/macros/s/#####/exec?key3=value3";
var res = UrlFetchApp.fetch(url, params);
Logger.log(res);

Sample scripts of client side by various languages

Now, you can see the following 11 sample scripts at https://gist.github.com/tanaikech/a72aab0242012362c46ec69031c720d5.

  1. curl
  2. Google Apps Script
  3. Javascript
  4. ajax
  5. Node.js
  6. axios
  7. angular
  8. go
  9. python
  10. php
  11. powershell

Status code from Web Apps

Here, I would like to introduce the status code returned from Web Apps.

Preparation:

As the preparation, Web Apps was deployed with "Execute the app as" and "Who has access to the app" as Me and Anyone, even anonymous, respectively. The sample script for Web Apps is as follows.

function doGet(e) {
  return ContentService.createTextOutput("GET: Done.");
}

Experiment:

Using Google Apps Script:

At first, the status code was checked using Google Apps Script. The deployed Web Apps was requested with the following script.

function myFunction() {
  var url_exec = "https://script.google.com/macros/s/###/exec";
  var url_dev = "https://script.google.com/macros/s/###/dev";
  var res = UrlFetchApp.fetchAll([{ url: url_exec }, { url: url_dev }]);
  res.forEach(function (e) {
    Logger.log(e.getResponseCode());
  });
}

In this case, the status code of 200 was obtained for both endpoints of exec and dev.

using Curl:

In order to retrieve the status code with curl, curl -s -o /dev/null -w "%{http_code}" http://www.example.org/ was used. This is from this thread. Here, the status code was investigated using the curl command. Because the curl can access by 2 kinds of request by the options as showing below.

  1. --include: Include the HTTP response headers in the output. The HTTP response headers can include things like server name, cookies, date of the document, HTTP version and more...

  2. --head: (HTTP FTP FILE) Fetch the headers only! HTTP-servers feature the command HEAD which this uses to get nothing but the header of a document. When used on an FTP or FILE file, curl displays the file size and last modification time only.

Using above options, the following 4 patterns were investigated.

  1. Request to the endpoint of https://script.google.com/macros/s/###/exec using the option --include.
    • curl -sL --include -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/exec"
    • 200 was returned.
  2. Request to the endpoint of https://script.google.com/macros/s/###/dev using the option --include.
    • curl -sL --include -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/dev"
    • 200 was returned.
  3. Request to the endpoint of https://script.google.com/macros/s/###/exec using the option --head.
    • curl -sL --head -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/exec"
    • 403 was returned.
  4. Request to the endpoint of https://script.google.com/macros/s/###/dev using the option --head.
    • curl -sL --head -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/dev"
    • 200 was returned.

As the result, it was found that when the Web Apps of the endpoint of https://script.google.com/macros/s/###/exec was requested with the option --head, the status code of 403 was obtained.

Result and discussions:

When the option --head is used for the curl command, from the document, this means that it requests only header and doesn't request the body. By this, it was found that the status code of 403 was returned.

Here, why was the status code of 200 returned for both options of --include and --head when it requests to the endpoint of dev? It is considered that the reason of this is due to that the login screen was returned. When the endpoint of dev is accessed, it is required to use the access token. When the access token is not used, the login screen is returned. In this case, the status code of 200 is returned. As the test case, when the access token is used for the endpoint of dev using below curl command,

curl -sL --head -H "Authorization: Bearer ###" -o /dev/null -w "%{http_code}" "https://script.google.com/macros/s/###/dev"

The status code of 403 was returned. From this result, the following results were obtained.

  • When only the header is retrieved under that the Web Apps works fine, 403 is returned.
  • When the login screen is returned, 200 is returned.

Applications for this situation

As one of applications using this situation, there is the registration of webhook at Trello's REST API.

When the Web Apps which was deployed as Execute the app as: Me and Who has access to the app: Anyone, even anonymous is registered as the webhook, an error of {"message":"URL (https://script.google.com/macros/s/###/exec) did not return 200 status code, got 403","error":"ERROR"} occurs. The reason of this error is due to above situation. So as the workaround for the registration, you can use the following flow.

  • Before you run the script, please set the Web Apps as follows. - "Execute the app as" and "Who has access to the app" are Me and Only myself, respectively.
  • After the response of like {"id":"###","description":"sample","idModel":"###","callbackURL":"https://script.google.com/macros/s/###/exec","active":true} was retrieved, please set the Web Apps as follows. - "Execute the app as" and "Who has access to the app" are Me and Anyone, even anonymous, respectively.

By this flow, the webhook can be used.

Sample script

This is a sample script of Google Apps Script for the registration of webhook URL.

var url = "https://api.trello.com/1/tokens/###/webhooks/?key=###";
var payload = {
  callbackURL: "https://script.google.com/macros/s/###/exec",
  idModel: "###",
  description: "sample",
};
var options = { method: "post", payload: payload };
var res = UrlFetchApp.fetch(url, options);
Logger.log(res.getContentText());

Concurrent access to Web Apps

  • Is there any limit on number of concurrent hits or simultaneous executions on Google App Script Web App

    • I answered to this thread in Stackoverflow. Ref
  • Benchmark: Concurrent Writing to Google Spreadsheet using Form

    • When the users try to write to a Spreadsheet using a form, the developers have to consider the concurrent submission from the form. For example, when multiple users submit the data with the form simultaneously, all data are possibly not to be saved to the Spreadsheet. So it is considered that it is important to know the information about the concurrent writing to Google Spreadsheet using a form. In this report, such a situation was investigated.

    • As the result, when the success rate for writing concurrently to Google Spreadsheet is investigated, it was found that the concurrent writing with Web Apps created by Google Apps Script was suitable rather than Google Form. The threshold number of users for succeeding to write all data to Spreadsheet was 60 for Web Apps and 35 for Google Form, respectively. And, when Web Apps is used, it was also found that Lock Service and the long wait time was definitely required to be used for the multiple submission.

Implementing Pseudo 2FA for Web Apps

In Google Apps Script, there is the Web Apps. When Web Apps is used, the users can execute Google Apps Script using HTML and Javascript. This can be applied to various applications. When the Web Apps is deployed with "Anyone", anyone can access the Web Apps. And, there is the case that Web Apps deployed with "Anyone" is required to be used. Under this condition, when 2 Factor Authentication (2FA) can be implemented, it is considered that the security can be higher and it leads to giving various directions for the applications using Web Apps. In this report, I would like to introduce the method for implementing the pseud 2FA for Web Apps deployed with “Anyone” using Google Apps Script.

You can see the detail of this report at https://gist.github.com/tanaikech/7a15164b1227e2ec2231fce24ae9daf2.

Request Web Apps using Fetch API of Javascript with the access token

In the current stage, when you want to request Web Apps with the access token, when the access token is including the request header, an error related to CORS occurs. Please be careful about this.

So, in this case, please include the access token in the query parameter. By this, the request can be worked. The sample script is as follows.

const accessToken = "###"; // Please set your access token.
const url = "https://script.google.com/macros/s/###/exec?access_token=" + accessToken;
fetch(url)
  .then((res) => res.text())
  .then((res) => console.log(res));

By this modification, you can access Web Apps with the access token.

By the way, for example, when the curl command is used, the access token can be included in the request header as follows.

$ curl -L \
-H "Authorization: Bearer ###" \
"https://script.google.com/macros/s/###/exec"

And also, the following curl command can be used.

$ curl -L "https://script.google.com/macros/s/###/exec?access_token=###"

Workarounds

1. Reflecting Latest Script to Deployed Web Apps without Redeploying

This report is a workaround for reflecting the latest Google Apps Script to the deployed Web Apps without redeploying. https://gist.github.com/tanaikech/e46def22cf106b012dfa5ad359b93d24

Implementing Pseudo 2FA for Web Apps

Applications

Here, I would like to introduce the applications of Web Apps. If you can introduce your applications, please tell me. I would like to introduce them here.

1. Converting from a1Notation to GridRange

This is a sample API for converting from a1Notation to GridRange. The GridRange is often used at Sheets API. Although I have thought that a1Notation is easy to use, there are no methods for converting it. So I created this as an API. I would like to introduce this as a sample for this report.

The sample script is as follows. At first, please copy and paste it to new standalone project.

function doGet(e) {
  var output = {};
  if (e.parameter.sheetid && e.parameter.a1notation) {
    output = {
      result: a1notation2gridrange1(
        e.parameter.sheetid,
        e.parameter.a1notation
      ),
    };
  } else {
    output = { error: "Wrong parameters." };
  }
  return ContentService.createTextOutput(JSON.stringify(output));
}

// https://gist.github.com/tanaikech/95c7cd650837f33a564babcaf013cae0
function a1notation2gridrange1(sheetid, a1notation) {
  try {
    var data = a1notation.match(/(^.+)!(.+):(.+$)/);
    var ss = SpreadsheetApp.openById(sheetid).getSheetByName(data[1]);
    var range = ss.getRange(data[2] + ":" + data[3]);
    var gridRange = {
      sheetId: ss.getSheetId(),
      startRowIndex: range.getRow() - 1,
      endRowIndex: range.getRow() - 1 + range.getNumRows(),
      startColumnIndex: range.getColumn() - 1,
      endColumnIndex: range.getColumn() - 1 + range.getNumColumns(),
    };
    if (!data[2].match(/[0-9]/)) delete gridRange.startRowIndex;
    if (!data[3].match(/[0-9]/)) delete gridRange.endRowIndex;
    return gridRange;
  } catch (e) {
    return e;
  }
}

And then, please deploy this as Web Apps. The condition is as follows.

  • "Execute the app as:" : User accessing the web app
  • "Who has access to the app:": Only myself

By this condition, owner and each client user can use Spreadsheets on own Google Drive. Before you access to Web Apps, please don't forget to share the project to users. The usage is as follows. This is a curl sample. But of course, you can also use this API using Google Apps Script.

curl -GL \
  -H "Authorization: Bearer ### your access token ###" \
  -d "sheetid=### spreadsheet ID ###" \
  -d "a1notation=Sheet1%21A1%3aB2" \
  "https://script.google.com/macros/s/#####/exec"

When you use this, please do URL encode for the range.

2. URL to upload to Google Drive

https://stackoverflow.com/questions/47833728/url-to-upload-to-google-drive

3. How to get a data range of the Sheet

https://stackoverflow.com/questions/48917258/how-to-get-a-data-range-of-the-sheet

4. Enhanced Custom Function for Google Spreadsheet using Web Apps as Wrapper

https://github.com/tanaikech/Enhanced-Custom-Function-for-Google-Spreadsheet-using-Web-Apps-as-Wrapper


Sample situations

Here, I would like to introduce the sample situations with Web Apps. Those are threads of Stackoverflow. You can see the actual situations using Web Apps from them.


References


Licence

MIT

Author

Tanaike

Update History

This repository has been created on April 26, 2018. After this repository was created, the information has continued to be grown now.

TOP

More Repositories

1

goodls

This is a CLI tool to download shared files and folders from Google Drive.
Go
388
star
2

taking-advantage-of-google-apps-script

Here, CLI tools, libraries, Add-ons, Reports, Benchmarks and Sample Scripts for taking advantage of Google Apps Script which are publishing in my blog, Gists and GitHub are summarized.
272
star
3

ggsrun

This is a CLI tool to execute Google Apps Script (GAS) at own terminal on local PC. Also this CLI tool can be used for managing files in Google Drive for OAuth2 and Service Account.
Go
117
star
4

ImgApp

This is a library of image tools for Google Apps Script.
CoffeeScript
110
star
5

ResumableUploadForGoogleDrive_js

This is a Javascript library to achieve the resumable upload for Google Drive.
JavaScript
71
star
6

goris

This is a CLI tool to search for images with Google Reverse Image Search (goris).
Go
68
star
7

Google-Apps-Script-Library-Database

This is for the Google Apps Script Library Database and a web application for searching the libraries..
HTML
57
star
8

RunAll

This is a library for running the concurrent processing using only native Google Apps Script (GAS).
CoffeeScript
55
star
9

FilesApp

FilesApp is a GAS library for retrieving file and folder list in Google Drive using Google Apps Script (GAS). Also this can create a tree from all files and folders in Google Drive.
JavaScript
42
star
10

Resumable_Upload_For_WebApps

This is a sample script for uploading files with large size (> 50 MB) at Web Apps using Google Apps Script (GAS). The resumable upload method is used for uploading files. This script can be also applied to the script using gapi of javascript.
HTML
39
star
11

DownloadLargeFilesByUrl

DownloadLargeFilesByUrl is a GAS library for downloading large files from URL to Google Drive using Google Apps Script (GAS).
JavaScript
38
star
12

GPhotoApp

This is a GAS library for retrieving and creating the albums and media items using Google Photo API using Google Apps Script (GAS).
JavaScript
38
star
13

DocsServiceApp

This is a Google Apps Script library for supporting Document service, Docs API, Spreadsheet service, Sheets API, Slides service and Slides API. The aim of this library is to compensate the processes that they services cannot achieve.
JavaScript
36
star
14

FetchApp

This is a GAS library for creating and requesting the type of multipart/form-data using Google Apps Script. This library enhances Class UelFetchApp of Google Apps Script.
JavaScript
36
star
15

CopyFolder

This is Google Apps Script library for copying folder on Google Drive.
JavaScript
31
star
16

BatchRequest

This is a library for running Batch Requests using Google Apps Script (GAS).
JavaScript
29
star
17

RichTextApp

This is a GAS library for copying the rich text with the text styles from Google Document to Google Spreadsheet or from Google Spreadsheet to Google Document using Google Apps Script (GAS). And, also the rich texts in the cells can be converted to HTML format.
JavaScript
29
star
18

OnedriveApp

This is a library of Google Apps Script for using Microsoft OneDrive.
HTML
25
star
19

HtmlFormApp

This is a Google Apps Script library for parsing the form object from HTML form and appending the submitted values to the Spreadsheet.
JavaScript
25
star
20

AsynchronousResumableUploadForGoogleDrive

This is a sample script for uploading multiple files with large size (> 50 MB) at the sidebar, dialog of Google Docs and Web Apps using the resumable upload of the asynchronous process with Javascript and Google Apps Script (GAS).
HTML
24
star
21

RangeListApp

RangeListApp is a GAS library for retrieving, putting and replacing values for Spreadsheet by a range list with a1Notation using Google Apps Script (GAS).
JavaScript
22
star
22

ManifestsApp

This is a Manifests library for Google Apps Scripts.
JavaScript
22
star
23

gdoctableapppy

This is a python library to manage the tables on Google Document using Google Docs API.
Python
21
star
24

ProjectApp2

This is a GAS project library for Google Apps Script (GAS). This library can be used for the projects of both standalone script type and container-bound script type.
JavaScript
18
star
25

getfilelistpy

This is a python library to retrieve the file list with the folder tree from the specific folder of Google Drive.
Python
18
star
26

go-getfilelist

This is a Golang library to retrieve the file list with the folder tree from the specific folder of Google Drive.
Go
16
star
27

FieldsBuilderForGoogleAPIs

FieldsBuilderForGoogleAPIs is a Web Application for building the fields value for using Google APIs. This is mainly used for developing the scripts for using Google APIs.
JavaScript
12
star
28

UnzipGs

This is a GAS library for unzipping a Zip file protected by a password using Google Apps Script.
JavaScript
12
star
29

GetEditType

GetEditType is a GAS library for retrieving the edit types of the OnEdit event trigger of Spreadsheet using Google Apps Script (GAS).
JavaScript
12
star
30

RearrangeScripts

This is a GAS application for rearranging Google Apps Scripts (GAS) in a project which can be seen at the script editor.
HTML
11
star
31

GetFileList_js

This is a Javascript library to retrieve the file list with the folder tree from the specific folder (publicly shared folders and own folders) of Google Drive.
JavaScript
10
star
32

Creating-PNG-Image-with-Alpha-Channel-using-Google-Apps-Script

This is a sample script for creating a PNG image with the alpha channel using Google Apps Script.
10
star
33

Enhanced-Custom-Function-for-Google-Spreadsheet-using-Web-Apps-as-Wrapper

This is a proposal of the enhanced custom function for Google Spreadsheet using Web Apps as the wrapper.
JavaScript
10
star
34

syncGoogleScriptRun

This is a Javascript library to use "google.script.run" with the synchronous process.
JavaScript
10
star
35

ZipFolder

This is a library for zipping a folder using Google Apps Scripts.
JavaScript
10
star
36

tanaikech.github.io

Blog (my memorandums)
HTML
9
star
37

GmailToList

This is a library for exporting all messages of Gmail as a list using Google Apps Script (GAS).
JavaScript
9
star
38

SOUWA_GAS

GAS library for summing string elements in an array at the high speed
JavaScript
9
star
39

OwnershipTransfer

This is a Google Apps Script library for achieving the ownership-transfer of the specific folder including the files and sub-folders using Drive API.
JavaScript
9
star
40

ProcessApp

This is a library for retrieving the process and information of Google Apps Script. For example, one of methods retrieves the total execution time of all functions executed by the time-driven trigger at owner's account.
JavaScript
9
star
41

DateFinder

DateFinder is a GAS library for searching the date objects from the cell range on the sheet in the Spreadsheet and retrieving the searched range as the RangeList object using Google Apps Script (GAS).
JavaScript
8
star
42

One_Time_Download_for_Google_Drive

This is a sample script for downloading files from Google Drive by the one time download method.
JavaScript
8
star
43

Linking-Google-Cloud-Platform-Project-to-Google-Apps-Script-Project-for-New-IDE

This is the document for linking Google Cloud Platform Project to Google Apps Script Project for New IDE. And also, several sample scripts using Google Apps Script API and Google Photos API are introduced.
8
star
44

node-getfilelist

This is a Node.js module to retrieve the file list with the folder tree from the specific folder of Google Drive.
JavaScript
7
star
45

ShapeApp

This is an add-on application for manipulating shapes on Google Slide. It can create and update shapes by inputting parameters, and can arrange shapes. This is made of Google Apps Scripts (GAS).
HTML
7
star
46

DocNamedRangeApp

This is a Google Apps Script library for managing the named range on Google Documents.
JavaScript
7
star
47

FileTransfer

How to transfer files for Google Drive without authorization.
JavaScript
7
star
48

Managing-A-Lot-Of-Google-Calendar-Events-using-Batch-Requests-with-Google-Apps-Script

These are the sample scripts for managing a lot of Google Calendar Events using the batch requests with Google Apps Script.
JavaScript
7
star
49

Safe-Uploading-for-Google-Drive-by-HTML-in-External-Server-using-Google-Apps-Script

This is a report for safe-uploading files to Google Drive by HTML put in the external server using Google Apps Script.
JavaScript
7
star
50

HtmlFormObjectParserForGoogleAppsScript_js

This is a Javascript library for sending the HTML form object to Google Apps Script using google.script.run.
JavaScript
7
star
51

Batch-Requests-for-Drive-API-using-Google-Apps-Script

These are the sample scripts of the batch requests for Drive API using Google Apps Script.
JavaScript
7
star
52

go-gdoctableapp

This is a Golang library for managing tables on Google Document using Google Docs API.
Go
6
star
53

File_Picker_using_Google_Apps_Script_and_Javascript_without_3rd_party

This is a sample script for the file picker using Google Apps Script and Javascript without 3rd party.
JavaScript
6
star
54

ProjectApp

This is a project library for Google Apps Script (GAS).
JavaScript
6
star
55

GASProjectApp

This is a Google Apps Script library for creating, updating and exporting Google Apps Script project of the standalone type using Drive API. In this case, Apps Script API is not used.
JavaScript
6
star
56

PDFApp

This is a Google Apps Script library for managing PDFs.
JavaScript
5
star
57

SimplePhotoGalleryUsingGoogleAppsScript

This is a sample script for achieving a simple photo gallery created by Google Slides and Web Apps using Google Apps Script.
HTML
5
star
58

FileUploadBydoPost_GAS

GAS and HTML for file Upload From HTML Form on local PC Using doPost()
HTML
5
star
59

getSpreadsheetByRange

This is a simple way for retrieving Spreadsheet ID from a range. As an application, we introduce the enhanced copyTo() which can copy from a range to other Spreadsheet.
5
star
60

GetAccessTokenFromServiceAccount_js

This is a Javascript library to retrieve the access token from the Google Service Account.
JavaScript
4
star
61

UtlApp

This is a Google Apps Script library including useful scripts for supporting to development of applications by Google Apps Script.
JavaScript
4
star
62

getcode

This is a Golang library to automatically get an authorization code for retrieving access token using OAuth2.
Go
4
star
63

RichTextAssistant

This is a GAS library for supporting editing RichText in Google Spreadsheet using Google Apps Script.
JavaScript
3
star
64

CropImageByBorder_js

This is a Javascript library for cropping images by the border.
JavaScript
3
star
65

tarUnarchiver-for-Google-Apps-Script

This is a script for extracting files from a tar file using Google Apps Script. This script was created by native Google Apps Script.
JavaScript
3
star
66

ArrangeStackingOrder

ArrangeStackingOrder is a GAS library for arranging the stacking order of page elements on Google Slides using Google Apps Script (GAS).
JavaScript
3
star
67

Notifying-Comments-at-Stackoverflow-by-Email

This is a script for sending an email when users got comments at Stackoverflow.
JavaScript
2
star
68

gislacks

This is a plugin of Sublime Text 3 for submitting files to both Gist and Slack.
Python
2
star
69

BatchRequest_js

This is a library for running Batch Requests for Google APIs using Javascript.
JavaScript
2
star
70

node-gdoctableapp

This is a Node.js module to manage the tables on Google Document using Google Docs API.
JavaScript
2
star
71

go-gettokenbyserviceaccount

This is a Golang library to retrieve access token from Service Account of Google without using Google's OAuth2 package.
Go
2
star
72

node-gbatchrequests

This is a Node.js module to run the batch requests of Google APIs.
JavaScript
2
star
73

GistChecker

This is a GAS library for notifying the change of number of comments, stars and forks of own Gists as an email using Google Apps Script.
JavaScript
2
star
74

image-storage

HTML
2
star
75

CreateImg

This Google Apps Script (GAS) library creates an image file from coordinate data.
JavaScript
2
star
76

gogauth

This is a CLI tool to easily retrieve access token for using APIs on Google.
Go
2
star
77

ConvertNFDtoNFC

This is a script for converting strings from NFD (Normalization Form Decomposition) to NFC (Normalization Form Composition) using Google Apps Script.
JavaScript
2
star
78

souwapy

Python library for summing string elements in an array at the high speed
Python
1
star
79

cui4netatmo

DOS batch file and UNIX shell script and one liner curl code for retrieving data from Netatmo
Batchfile
1
star
80

go-rearrange

This is a Golang library to interactively rearrange a text data on a terminal.
Go
1
star
81

Flexible-Labeling-for-Gmail-using-Gemini-API-with-Google-Apps-Script-Part-3

This report improves Gmail email labeling with Gemini API using JSON schema and leverages advancements in Gemini 1.5 Flash for faster processing.
JavaScript
1
star
82

gislack

This is a CLI tool to submit files to both Gist and Slack.
Go
1
star
83

gorearrange

This is a CLI tool to interactively rearrange a text data on a terminal.
Go
1
star
84

gonetatmo

This is a CLI tool to retrieve data from a personal weather station of Netatmo.
Go
1
star
85

Processing-Various-Types-of-Invoices-using-Gemini-1.5-API-with-Google-Apps-Script

This repository is for Parsing Invoices using Gemini 1.5 API with Google Apps Script.
JavaScript
1
star
86

TemplateApp

This is a Google Apps Script library for easily managing the template of Google Documents and Google Slides using Google Spreadsheet as a database using Google Apps Script.
JavaScript
1
star