In this codelab, you'll learn how to integrate Google Cloud Platform services into a Node.js web application to authenticate users, store data, upload images and use vision detection features.

What you'll learn

What you'll need

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would rate your experience with building node.js apps?

Novice Intermediate Proficient

How would you rate your experience with using Google Cloud Platform services?

Novice Intermediate Proficient

Codelab-at-a-conference setup

The instructor will be sharing with you temporary accounts with existing projects that are already setup so you do not need to worry about enabling billing or any cost associated with running this codelab. Note that all these accounts will be disabled soon after the codelab is over.

Once you have received a temporary username / password to login from the instructor, log into Google Cloud Console: https://console.cloud.google.com/.

Here's what you should see once logged in :

Note the project ID you were assigned ( "codelab-test003" in the screenshot above). It will be referred to later in this codelab as PROJECT_ID.

While 'Using Cloud Vision with Node.js' can be operated remotely from your laptop, in this codelab we will be using Google Cloud Shell, a command line environment running in the Cloud.

This Debian-based virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory, and runs on the Google Cloud, greatly enhancing network performance and authentication. This means that all you will need for this codelab is a browser (yes, it works on a Chromebook).

To activate Google Cloud Shell, from the developer console simply click the button on the top right-hand side (it should only take a few moments to provision and connect to the environment):

Once connected to the cloud shell, you should see that you are already authenticated and that the project is already set to your PROJECT_ID :

gcloud auth list

Command output

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Command output

[core]
project = <PROJECT_ID>

If for some reason the project is not set, simply issue the following command :

gcloud config set project <PROJECT_ID>

Looking for you PROJECT_ID? Check out what ID you used in the setup steps or look it up in the console dashboard :

IMPORTANT. Finally, set the default zone and project configuration:

gcloud config set compute/zone us-central1-f

You can pick and choose different zones too. Learn more about zones in Regions & Zones documentation.

In Cloud Shell on the command-line, run the following command to clone the Github repository:

git clone https://github.com/googlecodelabs/cloud-vision.git

Change directory into cloud-vision/start

cd cloud-vision/start

Next up

Next, you will run the sample application.

The sample has the following layout:

app.js                  /* Express.js web application */
config.js               /* Application configuration variables */
lib/
  cloudVisionClient.js  /* Cloud Vision client to consume the API */
  oauth2.js             /* OAuth2 client for login */
  routes.js             /* Application endpoints */
  storageClient.js      /* Cloud Storage client to consume the API */
package.json            /* npm package file including dependencies */
views/
  base.dust             /* HTML template */
public/
  style.css             /* CSS stylesheet */

To run the sample application in Cloud Shell let's perform the following steps:

1. Install dependencies. Enter the following command:

$ npm install
...

2. Run app.js to start the node.js server:

$ node app.js
App listening at http://:::8080

3. Click the "Web preview"icon that appears at the top left side of the cloud shell window and select "Preview on port 8080" to see the app in a web browser.

You will see a page that looks like this:

The application currently displays a not-yet-implemented user login. Let's fix that by setting up user authentication.

Summary

In this step, you set up and ran the codelab sample application.

Next up

Next, you will use OAuth 2.0 to add user login to the application and Google+ API to fetch user profile.

In this step, you will set up the Oauth 2.0 client.

First, you need to create a web application client for authentication.

The simplest authentication mechanism involves passing an API key directly to the service. In using the Vision API, we recommend that you enable an API key for testing purposes, and a service account for production usage. From the Google Cloud console :

  1. From the left navigation, click API Manager > Credentials
  2. Click Create credentials > OAuth Client ID
  3. Click Configure consent screen.
  4. Enter any product name you like, and fill in any relevant optional fields. Click Save.
  5. Choose Web application for the Application type.
  6. Under Name, enter any name you like.
  7. Under Authorized redirect URIs enter the URL you've been using to access the application from the browser:
https://8080-dot-<digit number>-dot-devshell.appspot.com/oauth2callback
  1. Click Create.
  2. Note the Client ID and Client Secret that are displayed since you'll need them for configuration.

Here is a screenshot of the page used to create the client ID :

And here is the resulting client ID and secret:

Update configuration

The node.js application needs to be configured to use the Client ID you created.

In the project directory, edit the config.js file.

1. Open the file in an editor. For example this command will open config.js using Nano:

nano -m config.js

2. Set the values of clientId, clientSecret, and redirectUrl with the values you set / obtained in the last step.

config.js

var clientId = 'REPLACE_WITH_YOUR_CLIENT_ID';
var clientSecret = 'REPLACE_WITH_YOUR_CLIENT_SECRET';
var redirectUrl = 'REPLACE_WITH_CALLBACK_URL_FROM_ABOVE';

Redirect to sign in screen

To begin, install the googleapis npm package, which you will use to generate the authentication URL and fetch the profile information for the logged in user, and also install cookie-session is a node.js middleware for providing signed cookie-based sessions.

npm install cookie-session googleapis --save

In the project directory, edit the app.js file.

1. Open the file in an editor. For example this command will open app.js using Nano:

nano -m app.js

2. Add the following code to register the OAuth2 middlewares and router:

app.js

var session = require('cookie-session');
// ...
 
// Set view template engine
// ... 

// Configure the session and session storage.
app.use(session({
  secret: config.secret,
  signed: true
}));


// OAuth2
var oauth2 = require('./lib/oauth2')(config.oauth2);
app.use(oauth2.router);
app.use(oauth2.aware);
app.use(oauth2.template);

// Configure routes
// ...

Fetch user profile

Enable the Google+ API so the application can call the API to fetch user profiles. From the Google Cloud Console :

  1. From the left navigation, click API Manager > Library, search for the "Google+ API".
  2. Click on Google+ API.
  3. Click Enable.

To fetch the profile of the authenticated user, the /oauth2callback route that Google Oauth2.0 redirects to calls getUserProfile from lib/oauth.js, passing it the provided ?code query string that can be used to fetch user's profile.

The returned user profile is stored in the application session via cookies.

Now, let's change the view to use the template values added by the OAuth2 middleware. In the project directory, edit the views/base.dust file.

1. Open the file in an editor. For example this command will open base.dust using Nano:

nano -m views/base.dust

2. Replace the next two sections:

base.dust

//...
<p class="navbar-text navbar-right">
  <a href="#">Login</a>
</p>

//...

<div class="alert alert-info">
  Please <strong> <a href="#">login</a> </strong> to continue
</div>

//...

with the following code:

base.dust

//...
<p class="navbar-text navbar-right">
  {?profile}
    {?profile.image}
      <img src="{profile.image.url}" width="24" class="img-circle">
    {/profile.image}
    <span>{profile.displayName} &nbsp;<a href="{logout}">(logout)</a></span>
  {:else}
    <a href="{login}">Login</a>
  {/profile}
</p>

//...
{?profile}
  <div class="alert alert-success">
    Welcome {profile.displayName}
  </div>
{:else}
  <div class="alert alert-info">
    Please <strong> <a href="{login}">login</a> </strong> to continue
  </div>
{/profile}

Restart the node application then try and sign in.

You should see your name and profile displayed!

Summary

In this step, you implemented an OAuth 2.0 web authentication flow and fetched the authenticated user's profile information.

Next up

Next, you will use Google Cloud Storage to upload images.

In this step, you will write the code to save image in Google Cloud Storage.

Set up Google Cloud Storage

The default bucket uses the same project ID for name:

  1. From the left navigation, click App Engine > Settings.
  2. Under Default Cloud Storage Bucket, click Create.
  3. Set public-read as the default object ACLs to existing and new objects in the bucket:
$ gsutil defacl set public-read gs://<your-project-id>.appspot.com
Setting default object ACL on gs://<your-project-id>.appspot.com/...

Next, you'll need to install the gcloud npm package, which you will use to interact with Cloud Storage, and the node.js middleware Multer for handling multipart/form-data forms for uploading files.

$ npm install gcloud multer --save

In the project directory, edit the config.js file.

1. Open the file in an editor. For example this command will open config.js using Nano:

$ nano -m config.js

2. Replace the placeholder value for projectId with the ID of the project that you created and also replace the placeholder value for bucketName with the name of the bucket you created:

config.js

var projectId = 'your-project-id';
var bucketName = 'your-bucket-name';

Now, let's register the cloud storage client.

In the project directory, edit the app.js file.

1. Open the file in an editor. For example this command will open app.js using Nano:

nano -m app.js

2. Add the following code so the storage client creates a bucket object that provides the API you will use to interact with your Google Cloud Storage bucket:

app.js

var storageClient = require('./lib/storageClient')(
  config.gcloud, 
  config.gcloudStorageBucket
);

// Configure routes
app.use('/', require('./lib/routes')(
  storageClient
));

To upload the image to Cloud Storage and return a publicly accessible URL for displaying the image and the object URI to be later used for the Cloud Vision API, add a 'post' function to lib/routes.js:

1. Open the file in an editor. For example this command will open routes.js using Nano:

nano -m lib/routes.js

2. Add the following 'post' function to lib/routes.js:

routes.js

var routes = function(storageClient) {
  //...

  router.post('/', 
    storageClient.multer.single('image'),
    storageClient.uploadToStorage,
    function(req, res) {
      if (req.file && req.file.cloudStoragePublicUrl) {
        res.render('base', {
          imageUrl: req.file.cloudStoragePublicUrl
        });
      }
  });

  return router;
};

The publicly accesible URL for the image file will be https://storage.googleapis.com/<bucket-name>/<filename> and the Google Cloud Storage image URI will be gs://bucket-name/object-name.

Finally, we need to change the views/base.dust file to display the form to upload images and to render the image using the Cloud Storage URL.

1. Open the file in an editor. For example this command will open base.dust using Nano:

nano -m views/base.dust

2. Replace the current {?profile} block with the following lines:

base.dust

//...
<h3>Google Cloud Vision</h3>

{?profile}
  <form action="/" method="post" enctype="multipart/form-data">
    <div class="form-group">
      <label for="image">Image</label>
      <input type="file" name="image" id="image" class="form-control">
    </div>

    <div class="form-group">
      <button type="submit" class="btn btn-success">Submit</button>
    </div>  
  </form>

  {?imageUrl}
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">Output</h3>
      </div>
      <div id="panel-body" class="panel-body">
        <img src="{.imageUrl}" height="600" width="600">
      </div>
    </div>
  {/imageUrl}
{:else}
//... 

Restart the node application and try uploading an image.

It should work!

Summary

In this step, you created a Google Cloud Storage bucket, uploaded images into it and rendered them using the public URL.

Next up

Next, you will set up the Google Cloud Vision API for your project.

In this step, you will set up Google Cloud Vision and configure the application to run detection on images from it.

Create Credentials

For the node.js application to access this project's services, it needs to be authenticated. The simplest authentication mechanism involves passing an API key directly to the service. In using the Vision API, we recommend that you enable an API key for testing purposes, and a service account for production usage.

  1. Visit Google Developers Console.
  2. Navigate to the project you created.
  3. From the left navigation, click API Manager > Credentials.
  4. Click Create credentials > API key.
  5. Choose Browser key, enter a name for this key and click Create.
  6. Copy the key from the dialog box and keep it secure.

Enable Cloud Vision API

The credentials you created allow your application to authenticate with Google Cloud Vision API. Enable the Cloud Vision API:

  1. From the left navigation, click API Manager > Overview, search for the "Cloud Vision API".
  2. Click on Cloud Vision API.
  3. Click Enable API.

Update configuration variables

To configure the node.js sample application to authenticate with the project you created, edit the config.js file in the project directory.

1. Open the file in an editor. For example this command will open config.js using Nano:

nano -m config.js

2. Replace the placeholder value for credentialsApiKey with the API key you created:

config.js

var credentialsApiKey = 'your-credentials-api-key';

Summary

In this step, you configured the node.js application with the credentials needed to consume the Cloud Vision API.

Next up

Next, you will update the application to send the images stored in Google Cloud Storage to the Cloud Vision API.

In this step, you'll write the code to configure the Cloud Vision client.

First, in the project directory, edit the app.js file.

1. Open the file in an editor. For example this command will open app.js using Nano:

nano -m app.js

2. Add the following code so the Cloud Vision client use the key created in the previous step to authenticate the calls to the API:

app.js

//...
var cloudVisionClient = require('./lib/cloudVisionClient')(
  config.gcloudVision
);

// Configure routes
app.use('/', require('./lib/routes')(
  storageClient,
  cloudVisionClient
));

Now, we need to modify lib/routes.js file, to expose the different feature types available in the API through the cloudVisionClient to run detection on images and to add the call to the API to send the Google Cloud Storage URI, how many results we want to get and the feature type:

1. Open the file in an editor. For example this command will open routes.js using Nano:

nano -m lib/routes.js

2. Edit the file:

routes.js

// ...
var assign = require('lodash').assign;
var values = require('lodash').values;

var routes = function(storageClient, cloudVisionClient) {
  var defaultContext = {
    featureTypes: values(cloudVisionClient.featureTypes)
  };

  router.get('/', function(req, res) {
    res.render('base', defaultContext);
  });

  router.post('/', 
    storageClient.multer.single('image'),
    storageClient.uploadToStorage,
    function(req, res) {
      var context = {
        vision: {}
      };

      if (req.file && req.file.cloudStoragePublicUrl) {
        cloudVisionClient.detectImage(
          req.file.cloudStorageUri, 
          req.body.imageType, 
          req.body.maxResults,
          function(error, response) {
            if (error) {
              context.error = error;
            } else {
              // Indent 2 spaces the json response if exists.
              context.vision.prettyprint = response ? 
                  JSON.stringify(response, null, 2) : null;
              context.vision.imageUrl = req.file.cloudStoragePublicUrl;
              context.vision.response = JSON.stringify(response.responses);
            }

            res.render('base', assign(context, defaultContext));
          }
        );        
      } else {
        context.error = 'Something went wrong uploading the image!';
        res.render('base', assign(context, defaultContext));
      }
  });
//...

Render Cloud Vision API response

We need to change the views/base.dust file to add a select drop-down menu element containing the feature types obtained by the client. We also need to add one more select drop-down menu element to pick how many results we want in the response and the output container.

1. Open the file in an editor. For example this command will open base.dust using Nano:

nano -m views/base.dust

2. Using the following code, replace the {?profile} block:

base.dust

//...
<h3>Google Cloud Vision</h3>

{?profile}
  <form action="/" method="post" enctype="multipart/form-data">
    <div class="form-group">
      <label for="image">Image</label>
      <input type="file" name="image" id="image" class="form-control">
    </div>

    {?featureTypes}
      <div class="form-group">
        <label for="imageType">Type of image feature:</label>
        <select class="form-control" name="imageType">
          {#featureTypes}
            <option>{.}</option>
          {/featureTypes}
        </select>
      </div>

      <div class="form-group">
        <label for="maxResults">Max results:</label>
        <select class="form-control" name="maxResults">
           <option>1</option>
           <option>2</option>
           <option>3</option>
           <option>4</option>
           <option>5</option>
           <option>6</option>
           <option>7</option>
           <option>8</option>
           <option>9</option>
           <option>10</option>
        </select>
      </div>
    {/featureTypes}
    <div class="form-group">
      <button type="submit" class="btn btn-success">Submit</button>
    </div>  
  </form>

  {?vision}
    {#vision}
      <div class="panel panel-default">
        <div class="panel-heading">
          <h3 class="panel-title">Output</h3>
        </div>
        <div id="panel-body" class="panel-body">
          {?.prettyprint}
            <pre class="prettyprint">{.prettyprint}</pre>
          {/.prettyprint}
          <canvas id="panel-canvas" class="canvas"></canvas>
          <script>
            initCanvas('{.imageUrl}', '{.response|s}');
          </script>
        </div>
      </div>
    {/vision}
  {/vision}

  {?error}
    <div class="alert alert-danger" role="alert">{error}</div>
  {/error}
{:else}
//... 

Let's restart node application and try uploading this image, select "Execute Image Content Analysis on the entire image and return", leave the results as 2 and submit.

You should get a label annotation saying there is a dog in the image!

Summary

In this step, you configured the Cloud Vision client to send images from Google Cloud Storage to the Cloud Vision API to run detection of images.

You learned how to integrate Cloud Storage and Cloud Vision into a node.js application and use OAuth 2.0 to authenticate users!

What we've covered

Next Steps

Give us your feedback