DEV Community

Dustin Ingram for Google Cloud

Posted on • Updated on

Hitting a Cloud Function when you submit a Google Form

Google Forms is a great tool--easy to create, easy to use, etc. I was recently at a meetup talking to users about Google Cloud Platform and someone said they wished they could hook a Google Form up to a Google Cloud Function.

After thinking for a second, I thought "this must be possible". Although there's not usually a lot of direct interoperability between G Suite and Google Cloud, I knew that you could write an Apps Script trigger for most Google Docs, which would let you make HTTP requests, and that Cloud Functions can accept arbitrary HTTP requests as events, so there's no reason this shouldn't work.

And in fact, it totally works!

Writing your Cloud Function

There's really nothing special about the Cloud Function you'll create for this: it's just like any other Cloud Function that accepts a HTTP request. Let's assume we're going to be passing JSON back and forth as the payload:

The function would look something like this:

def form_trigger(request):
    payload = request.get_json(silent=True)
    print(f"Payload was: {payload}")
    return "OK"

This will get the JSON from the POST request, print it to our logs, and just return an "OK". Obviously you can do then whatever you want with the payload at this point: store it in your database, kick off a job, etc.

Deploy that function with gcloud functions deploy form_trigger --trigger-http --runtime python37 and move on to the next step.

Creating your Google Form

The Google Form you create will just be like any other form: you can have multi-part questions, multiple-choice questions, free-form questions, etc.

Creating a script for your form

Here's where we can start connecting the dots. First, literally select the three dots in the menu when you're editing your form:

From this menu, choose "Script editor" to get taken to the Apps Script editor for this form. This should give you a file named Code.gs with an empty function like so:

function myFunction() {

}

We're going to update it to be something like the following:

// Replace with the URL to your deployed Cloud Function
var url = "<YOUR CLOUD FUNCTION URL>"

// This function will be called when the form is submitted
function onSubmit(event) {

  // The event is a FormResponse object:
  // https://developers.google.com/apps-script/reference/forms/form-response
  var formResponse = event.response;

  // Gets all ItemResponses contained in the form response
  // https://developers.google.com/apps-script/reference/forms/form-response#getItemResponses()
  var itemResponses = formResponse.getItemResponses();

  // Gets the actual response strings from the array of ItemResponses
  var responses = itemResponses.map(function getResponse(e) { return e.getResponse(); });

  // Post the payload as JSON to our Cloud Function  
  UrlFetchApp.fetch(
    url,
    {
      "method": "post",
      "payload": JSON.stringify({
        "responses": responses
      })
    };
  );
}

Make sure to update the url variable with the full URL to your deployed Cloud Function.

Adding a trigger

Now, from the script editor, click on "Edit" > "Current project's triggers" . This will prompt you to give your project a name, and then take you to the G Suite Developer Hub, and show you all the triggers for your project (there should be none).

In the bottom right corner, select "+ Add Trigger" to add a new trigger:

The dialog should default to the onSubmit function you declared for your form, otherwise select it.

You should also be sure to change the "Select event type" field from "On open" to "On form submit".

This will create a popup window to allow Apps Script to view and modify your form.

Finally, save your trigger and it should appear in the list of triggers.

Conclusion

At this point, your form is fully connected to Cloud Functions! You can submit some test responses and you should see the responses appearing in the logs for your function.

From here, you can hook the function up to other services, or do things conditionally based on the responses, and you shouldn't need to write additional Apps Script to make it happen.

Top comments (16)

Collapse
 
jouwert profile image
Jouwert van Geene

I am a complete newby trying to connect my google forms to Google Cloud for use in Firebase for a corona-response team in the Netherlands. I get an error running the first Cloud Function.
The trigger seems ok , but cannot be tested

Collapse
 
fusionx1 profile image
Paul Jebulan de Paula

Having the same issue

Collapse
 
di profile image
Dustin Ingram

Hi Jouwert, happy to help. What's the error?

Collapse
 
jouwert profile image
Jouwert van Geene • Edited

I am trying to upload screenshot but I fail ...
This is what Google Cloud gives me back:
Implementatiefout:
Function failed on loading user code. Error message: Code in file index.js can't be loaded.
Is there a syntax error in your code?
Detailed stack trace: /srv/index.js:1
(function (exports, require, module, __filename, __dirname) { def form_trigger(request):
^^^^^^^^^^^^

SyntaxError: Unexpected identifier
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:617:28)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
at Module.require (module.js:597:17)
at require (internal/module.js:11:18)
at getUserFunction (/worker/worker.js:439:24)

Thread Thread
 
jouwert profile image
Jouwert van Geene

The trigger script in my google form is

// Replace with the URL to your deployed Cloud Function
var url = "us-central1-inspired-rush-271907.c..."

// This function will be called when the form is submitted
function onSubmit(event) {

// The event is a FormResponse object:
// developers.google.com/apps-script/...
var formResponse = event.response;

// Gets all ItemResponses contained in the form response
// developers.google.com/apps-script/...
var itemResponses = formResponse.getItemResponses();

// Gets the actual response strings from the array of ItemResponses
var responses = itemResponses.map(function getResponse(e) { return e.getResponse(); });

// Post the payload as JSON to our Cloud Function

UrlFetchApp.fetch(
url,
{
"method": "post",
"payload": JSON.stringify({
"responses": responses
})
});
};

Thread Thread
 
jouwert profile image
Jouwert van Geene

But maybe the Cloud Function is wrong. I was not so sure as to how to implement this script from your instruction:

def form_trigger(request):
payload = request.get_json(silent=True)
print(f"Payload was: {payload}")

return "OK"

Collapse
 
fusionx1 profile image
Paul Jebulan de Paula

Hi Im also having a problem after setting it up my google form and cloud function. I tested them both separately, like the trigger works completely without fail and cloud function work if executed directly cloud function dashboard i can see right away the logs however when doing an actual test to the form like submitting the form i don't get any cloud function logs.

Collapse
 
di profile image
Dustin Ingram

Hi there, can you share some more details? What does your Cloud Functions and Apps Script trigger look like?

Collapse
 
fusionx1 profile image
Paul Jebulan de Paula

Hi Dustin, I'm just following the whole instruction you shared. But I cant catch it from the logs it seems that its not being executed when i'm submitting a form.

Thread Thread
 
di profile image
Dustin Ingram

Perhaps a silly question, but did you make sure to update var url = "<YOUR CLOUD FUNCTION URL>"?

Thread Thread
 
fusionx1 profile image
Paul Jebulan de Paula • Edited

ow yes and it works and it prints ok when accessing that url - us-central1-xxxxxx-csapps.cloudfun...

From the logs i can only see the image attached when I'm manually triggering it from the dashboard. See dev-to-uploads.s3.amazonaws.com/i/...

Thread Thread
 
fusionx1 profile image
Paul Jebulan de Paula

It seems that this doesn't work anymore. Confirmed that trigger doesn't execute the URL anymore.

Collapse
 
abejr profile image
abejr

I couldn't get it to work, for some reason the data I was receiving in Firebase Cloud Functions was malformed, I had to add the following to the fetch parameters:
contentType: "application/json"
Then, the payload could be accessed from the function directly from the body object
PS found this solution from stackoverflow.com/questions/629020...

Collapse
 
ericad profile image
ericad

Thanks for the post. I tried to add this functionality to a form on my own google site, and I mostly got it working; however I'm stuck on the part where you use JSON to pass things between google scripts. The google script throws an error when I include one of the semicolons that are in your script, but leaving it off results in nothing being passed to the google cloud function. I attached something that shows what I am trying to do and how I'm trying to do it. Any help debugging the JSON statement would be appreciated. Thanks!

Collapse
 
fusionx1 profile image
Paul Jebulan de Paula

Where you able to run it? We may have a similar issue. Do you see json data from gcp logs?

Collapse
 
aris_vrakas_4e913725b8bdb profile image
Aris Vrakas

Is there a way to integrate Google Cloud functions in forms created via API?