Home / DialogFlow ES / Deploy NodeJS Webhook to Google Cloud
DialogFlow ES | NodeJS | Webhooks

Deploy NodeJS Webhook to Google Cloud

This website contains affiliate links. See the disclosure page for more details. 

This tutorial was a series of posts which was first published in October 2017. There have been many updates in Google Cloud after this tutorial was first created, so it may not be the best learning resource for this topic.

A couple of things to note:

  • almost certainly, the interface will look different today and the screenshots may not be up to date
  • whenever I ask you to click on a certain link, it is understood that you are already logged in to your Google account (that is, many of these links take you directly to specific feature pages inside the Google Cloud Console)

If you would like me to update this tutorial, please leave a comment below. If I get 5 or more comments, I will update this guide.

Introduction

In this series, I will walk you step by step through the process of deploying a webhook for DialogFlow on the Google Cloud.

We will be using the NodeJS programming language for the webhook.

Create index.js

The first step is to create a file called index.js and copy/paste the following code into the file.

/*
* HTTP Cloud Function.
*
* @param {Object} req Cloud Function request context.
* @param {Object} res Cloud Function response context.
*/
exports.helloHttp = function helloHttp (req, res) {
  response = "This is a sample response from your webhook!" //Default response from the webhook to show it's working

  res.setHeader('Content-Type', 'application/json'); //Requires application/json MIME type
  res.send(JSON.stringify({ "speech": response, "displayText": response 
  //"speech" is the spoken version of the response, "displayText" is the visual version
  }));
};

Create Google Account

In this step, you should go ahead and create a Google Account if you don’t have one. I am supposing that most people who are reading this tutorial do have a Google account, but well, it is one of the steps in the tutorial. 🙂

Create a Google Cloud Platform project

In this step, we will create a Google Cloud Platform project.

Visit this link while being signed in to Google.

Create a new project and give it a suitable name.

As you can see, Google Cloud will select a project ID based on the project name.

Enable Billing

In this step, you should enable billing for your newly created project.

Click this link to go to the appropriate page.

On the left menu, select Billing.

Once you select Billing, you should be able to Enable Billing for your account (my view will be different as I have already enabled it).

Enable the Cloud Functions API

In this step, you will enable the Cloud Functions API.

First, go to this link while you are signed in.

Next select the project that you just created.

Click on Continue. You will see the popup “Enabling API” at the bottom of the browser window for quite a while (about 1 minute for me):

And when its done, you should see the following success message

Note: Obviously these screenshots may not be the same always as Google keeps updating its services. But hopefully they give you a good idea of the basic steps required.

Install and initialize Google Cloud SDK

In this step, you must install the Google Cloud SDK and initialize it.

To install the SDK, go to this link and follow the steps based on whichever OS you are using.

Very important

Be sure to run the gcloud init command.

For example, on the Mac, this is the command you will run to initialize the SDK.

When I ran gcloud init on my machine, I had to go through a few steps. The prompts below may be slightly different for you since you are running the gcloud init command for the first time.

In the prompt below, choose the number corresponding to the project which you just created.

The next prompt asks if you would like to enable Compute Engine on the project. I selected Yes, although I don’t yet have a complete understanding of why this prompt shows up.

Your steps might be a little different depending on your Google Cloud configuration and such (also, you probably will not have as many projects as I do), but the important thing is to see the message highlighted below.

You are now ready to move on to the next step.

Update and install GCloud components

This is the “missing” step from the documentation. If you notice the documentation on the following page, it says we should do steps 1 – 5 in the page it links to.

Actually you need to do steps 1 -6.

So first you should run gcloud components update

You should see this message when it is done.

When I ran “gcloud install component beta” I got a message that the components were up to date.

With all the components up to date, we can now move on to the next step.

Create storage bucket

In this step, we will create a Cloud Storage Bucket.

What is a bucket? This is what we have from the documentation.

Buckets are the basic containers that hold your data. Everything that you store in Google Cloud Storage must be contained in a bucket.

So we need a container to hold our data, but we also apparently need it to just execute some code using cloud functions.

On the Google Cloud Console, select Storage from the Cloud console’s left menu.

You should see the following screen. Click on the Create bucket button.

Give your bucket an appropriate name. As the documentation points out, don’t put sensitive values into the bucket name because others can discover your bucket name.

A quick note about the “Add label”. This is what you see when you open the “Add Label” accordion.

Labels are like metadata you wish to associate with the cloud storage bucket. Here is how the documentation explains it.

Bucket labels are key:value metadata pairs that allow you to group your buckets along with other Google Cloud Platform resources such as virtual machine instances and persistent disks. For example, you can use labels to create a team key that has values alpha, beta, and delta, and apply the team:alpha, team:beta, and team:delta labels to different buckets in order to indicate which team is associated with those buckets.

We don’t use them for this example, but good to know. 🙂

When you go ahead and create the bucket, this is what you see.

Now click on the Buckets link from the breadcrumb on the top, and you should see something like this. Copy the bucket name and save it someplace handy. You will be needing it for the remainder of this guide.

Deploy index.js

Now that we have our bucket name, let us go ahead and deploy the index.js cloud function.

You will use the following command:

When you run the following command

gcloud beta functions deploy helloHttp --stage-bucket [BUCKET_NAME] --trigger-http

You will see an output similar to below where it asks to enable cloudfunctions.googleapis.com. Select Y for yes.

Once that is done, you should see the following success message in the console along with details about the deployed function.

Also note down the url under the httpsTrigger, you will need it for the next step.

Create a weather intent

Log into DialogFlow and create a DialogFlow agent.

Now add a new intent called AskForWeather in your agent, and simply have the word weather as the userSays phrase. In the Intent’s response, simply type “This is the default text response defined inside the intent.” See image below to see how to define the intent.

This is a very simple intent. Now, in your test console type “weather” and press Return. You will see the response we added above.

So what happened here?

It is simply DialogFlow responding to user input as it normally does.

And the Google documentation is trying to show a simple “before and after” scenario, although it isn’t fully explained. 🙂

But in the next step, you will understand what is happening once we enable fulfillment.

Hook up the webhook

Now go to the Fulfillment section in your DialogFlow agent and add the URL you received from deploying your cloud function as your webhook(the one under the httpsTrigger).

In your AskForWeather intent, at the very bottom, under the Fulfillment section, check the box which says “Use webhook”

Now when you type “weather” into the test console, this is what you get.

So why did the response change? Where did the new response message come from?

From the webhook, of course!

Here you see it in the index.js file you defined way back.

So let us take a moment and reflect on what we have done in this tutorial till this point. We have

  • set up all the stuff on Google properly
  • created a tiny little webhook function which simply says “This is a sample response from your webhook”
  • deployed the function successfully to the Google Cloud
  • been able to successfully interact with the Google Cloud Function from our DialogFlow agent

If you stopped right here, you would already have the basic template for deploying a NodeJS webhook to the Google Cloud.

But wait, there’s more. 😉

Sign Up for the World Weather Online service

Now we move on to some more advanced stuff.

But first, we need to register for the World Weather Online’s API service. So go to World Weather Online and sign up for an API key.

Note: the service is not free. You have some limits on the number of API calls you can make. But you don’t need to provide credit card info to sign up.

Once you sign up, you will receive an API key like the following. Copy the API key someplace safe.

Update index.js with weather webhook code

Now go back to the index.js file and replace the code inside the file with the following code (this is the same as the sample code here).

'use strict';
const http = require('http');
const host = 'api.worldweatheronline.com';
const wwoApiKey = '[YOUR_API_KEY]';
exports.weatherWebhook = (req, res) => {
  // Get the city and date from the request
  let city = req.body.result.parameters['geo-city']; // city is a required param
  // Get the date for the weather forecast (if present)
  let date = '';
  if (req.body.result.parameters['date']) {
    date = req.body.result.parameters['date'];
    console.log('Date: ' + date);
  }
  // Call the weather API
  callWeatherApi(city, date).then((output) => {
    // Return the results of the weather API to API.AI
    res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({ 'speech': output, 'displayText': output }));
  }).catch((error) => {
    // If there is an error let the user know
    res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({ 'speech': error, 'displayText': error }));
  });
};
function callWeatherApi (city, date) {
  return new Promise((resolve, reject) => {
    // Create the path for the HTTP request to get the weather
    let path = '/premium/v1/weather.ashx?format=json&num_of_days=1' +
      '&q=' + encodeURIComponent(city) + '&key=' + wwoApiKey + '&date=' + date;
    console.log('API Request: ' + host + path);
    // Make the HTTP request to get the weather
    http.get({host: host, path: path}, (res) => {
      let body = ''; // var to store the response chunks
      res.on('data', (d) => { body += d; }); // store each response chunk
      res.on('end', () => {
        // After all the data has been received parse the JSON for desired data
        let response = JSON.parse(body);
        let forecast = response['data']['weather'][0];
        let location = response['data']['request'][0];
        let conditions = response['data']['current_condition'][0];
        let currentConditions = conditions['weatherDesc'][0]['value'];
        // Create response
        let output = `Current conditions in the ${location['type']} 
        ${location['query']} are ${currentConditions} with a projected high of
        ${forecast['maxtempC']}°C or ${forecast['maxtempF']}°F and a low of 
        ${forecast['mintempC']}°C or ${forecast['mintempF']}°F on 
        ${forecast['date']}.`;
        // Resolve the promise with the output text
        console.log(output);
        resolve(output);
      });
      res.on('error', (error) => {
        reject(error);
      });
    });
  });
}

Now add the API key from World Weather Online into line number 4 above, as shown in the screenshot.

Update the cloud function

Now update the cloud function with the command below. Notice that the name of the function has changed from helloHttp to weatherWebhook. Be sure to use your actual bucket name rather than the placeholder below.

gcloud beta functions deploy weatherWebhook –stage-bucket [BUCKET_NAME] –trigger-http

Everything else is the same as the previous time you used this function.

Just like last time, make sure to take a note of the URL under httpsTrigger. Note: The last part of the URL will be different from the one which was returned for the helloHttp function because we are using a different function name this time. 

Update agent to get city

Back inside your API.AI agent, first copy/paste your new httpsTrigger URL into the Fulfillment section.

In the AskForWeather intent, add a required parameter of type @sys.geo-city and call it “geo-city”. Note: you must use this exact name and system entity type. Don’t use your own variable name, at least not at this point.

Under prompts, you can have something like “Which city?”

Remember to Save the intent.

Get weather for city

Now we are ready to test our weather webhook end to end.

In your test console, type weather.

You don’t get a response. You just get a prompt asking you for the city.

This is expected behavior. When we added a required parameter in the previous step, we were using something called “slot-filling”. The basic idea behind slot filling is: we are trying to collect a list of values from the user before we can get them the answer. In this case, we obviously need the city name before we can provide an answer. So we make the city name a required parameter.

(Generally speaking, I am not a fan of slot filling. But using it for small demo tutorials is OK).

Now type in a city name. I tried London.

And as soon as you input the city name, you get your response with the complete weather details summary for today.

Next steps

That brings us to the end of the guide and I hope you found it useful. If you have been able to follow along till this step, you now have a working NodeJS based webhook deployed on Google Cloud.

Now you can try to do the following:

  • use multiple intents and learn how to handle them using the action parameter
  • call a database and get some values
  • try using other APIs (e.g. build the Chuck Norris bot using NodeJS)

Live Webinar

The recently released Zoho SalesIQ v2 allows non-programmers to build chatbots using an easy-to-use code less bot builder. What is really unique about Zoho SalesIQ is the fact that you can also integrate AI into their code less bot builder. In my Zoho SalesIQ chatbots course, I explain how to use Zoho SalesIQ to add a chatbot to your website.

"The magic key I needed as a non-programmer"

The custom payload generator was the magic key I needed (as a non-programmer) to build a good demo with rich responses in DialogFlow Messenger. I've only used it for 30 minutes and am thrilled. I've spent hours trying to figure out some of the intricacies of DialogFlow on my own. Over and over, I kept coming back to Aravind's tutorials available on-line. I trust the other functionalities I learn to use in the app will save me additional time and heartburn.

- Kathleen R
Cofounder, gathrHealth

Similar Posts