http://www.roitraining.com

In this lab, you will write a Node.js Express application. Then, you will deploy the application to Google Cloud Functions.

Cloud Functions is a serverless, Node.js environment provided by Google Cloud Platform. Cloud Functions requires no administration and is easy to use. It is also very inexpensive. At the time of this writing, the cost is 40 cents per million invocations, with the first 2 million requests free.

Cloud Functions is simple to use! The majority of the work in this lab will be building the Express Web App.

Once you have a Node.js application running, it will be a simple task to deploy it Cloud Functions.

What you need

To complete this lab, you need:

What you learn

In this lab, you will:

Before you can deploy an application to Google Cloud Functions, you have to have something to deploy. Any Node.js application can be deployed. Lots of developers like Express, so let's use it.

If you aren't familiar with Express, it's like Flask in Python or ASP.NET in C#. More information can be found here: https://expressjs.com/

Step 1

Log onto the Google Cloud Platform web console at http://console.cloud.google.com.

Select a project to use for this lab, or create a new project now. If you don't know how to create a project, see the lab Getting Started with GCP.

Step 2

From the Products and Services menu, choose Cloud Functions. If you see a message saying Cloud Functions is not enabled as shown below, then click the Enable API button.

Step 3

Open Google Cloud Shell by clicking its icon in the toolbar (it is the icon that looks like a command prompt).

The first time you start Google Cloud Shell, the dialog shown below will pop up asking you to agree to the terms of service. If this happens, then select Yes and then click the Start Cloud Shell link.

Step 4

First, you need a folder to put your program in. Run the command below to create a folder called converter-cloud-function, and then change to that folder.

mkdir converter-cloud-function
cd converter-cloud-function

Step 5

Google Cloud Shell includes an integrated code editor, which might be easy to use to create your program. To open it, click the icon that looks like a pencil in the Cloud Shell toolbar.

Once the code editor is launched, it should look similar to what is shown below.

Step 6

In the left-hand navigation pane of the code editor, select the converter-cloud-function folder you just created.

Now, right-click the folder and select New | File. Name the new file app.js.

Step 7

Paste the following code in the app.js file.

// These are the Node.js modules used for this Express app.
// They are installed using NPM
var express = require('express');
var cors = require("cors");
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

// These are the modules that we write.
// They are specific to our application.
var index = require('./routes/index');
var conversions = require('./routes/conversions');

// This creates the Express app which is configured below.  
var app = express();

// Set up the view engine.
// Views are in a folder called "views"
// Handlebars (hbs) is used for the templating engine.
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

// Standard Express stuff
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(cors());

// This configures the routes.
// Requests for the root folder are handled by the index module.
// Requests for the /api/conversions route are handle by the 
// conversions module.
// These modules were added above.
app.use('/', index);
app.use('/api/conversions', conversions);

// All other requests are handled by the index module
app.use('*', index);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

// Important later!  This exports the app object as a module.
// This comes into play when we deploy the application to 
// Cloud Functions.
module.exports = app;

A lot of this is just boilerplate Express code. Take a couple minutes to read the comments in the code.

Step 8

Right-click the converter-cloud-function folder again and create a new file called package.json.

Step 9

Paste the following code in the package.json file.

{
  "name": "express-app",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.18.2",
    "cookie-parser": "~1.4.3",
    "cors": "^2.8.4",
    "debug": "~2.6.9",
    "express": "~4.15.5",
    "hbs": "~4.0.1",
    "morgan": "~1.9.0",
    "request": "^2.83.0"
  }
}

Step 10

Right-click the converter-cloud-function folder again and this time create a folder called bin.

Now, right-click the bin folder and create a file called www.

Paste the following code in the www file.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('express-app:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '8081');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  console.log('Listening on ' + bind);
}

You are going to create a simple website that will do temperature conversion. The site is shown below.

Step 1

Right-click the converter-cloud-function folder again and this time create a folder called views.

Step 2

Inside the views folder create a file called layout.hbs, and then paste the following code into that file. This file is shared by all the views.

<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
      <meta http-equiv="content-type" content="text/html; charset=utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">

      <!-- Latest compiled and minified CSS -->
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
            integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

      <!-- Optional theme -->
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
            integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

      <!-- Latest compiled and minified JavaScript -->
      <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
              integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
              crossorigin="anonymous"></script>
  </head>
  <body>
    <div class="container">
        {{{body}}}
      </div>

  </body>
</html>

Step 3

Also inside the views folder, create a file called index.hbs, and then paste the following code into that file.

<div class="jumbotron">
    <div class="container">
        <h1>{{title}}</h1>
        <p>Welcome to {{title}}</p>
    </div>
</div>

<div>
    <form method="post">

        <div><h3>Value to Convert:</h3><input name="valuetoconvert" value="{{value}}" /></div>
        <div>
            <input type="submit" value="Celsius" name="conversion">
            <input type="submit" value="Fahrenheit" name="conversion" />
        </div>
    </form>
    <h2>{{answer}}</h2>
</div>

Step 1

Right-click the converter-cloud-function folder again and this time create a folder called routes.

Step 2

Inside the routes folder create a file called index.js, and then paste the following code into that file. This is the controller for the home route (/).

var express = require('express');
var router = express.Router();
var request = require('request');

/* GET home page. */
router.get('/', function(req, res) {

  var model = {
    title:'Converter',
    value:'-40',
    answer:'-40'
  };

  res.render('index', model);
});


router.post('/', function(req, res) {
  var valueToConvert = req.body.valuetoconvert;
  var whichFunction;
  
  if(req.body.conversion === 'Celsius'){
    whichFunction = 'to-celsius';
  }
  else{
    whichFunction = 'to-fahrenheit';
  }
  
  var URL = "https://us-central1-dev-ops-demo.cloudfunctions.net/converter/api/conversions/";

  request.get({ url: URL + whichFunction + "/" +  valueToConvert},
      function(error, response, body) {
        if (!error && response.statusCode === 200) {

          var data = JSON.parse(body);

          var model = {
            title:'Converter',
            value:data.valueToConvert,
            answer:data.convertedValue
          };

          res.render('index', model);
        }
      });
});

module.exports = router;

Step 3

Again inside the routes folder, create a file called conversions.js, and then paste the following code into that file. This is the controller for the Conversions API we are going to build.

var express = require('express');
var router = express.Router();

router.get('/to-fahrenheit/:temp/', function(req, res, next) {

    var temp= Number(req.params.temp);
    if(!temp) temp = 0.0;

    var fahr = temp * 9.0 / 5.0 + 32.0;

    var answer = {valueToConvert: temp,
        convertedValue: fahr};

    res.send(answer);
});

router.get('/to-celsius/:temp/', function(req, res, next) {

    var temp= Number(req.params.temp);
    if(!temp) temp = 0.0;

    var cels = (temp - 32.0) * 5.0 / 9.0;
    var answer = {valueToConvert: temp,
        convertedValue: cels};

    res.send(answer);
});

module.exports = router;

Step 4

At this point, I wouldn't be surprised is you are confused by the routes. To review, in the app.js file the Express application is configured. Buried in that code are the following two lines:

app.use('/', index);

app.use('/api/conversions', conversions);

These lines define the routing. If a request is made to the the home route (/), then respond using the index module. If a request is made to the route /api/conversions then respond using the conversions module.

Let's test this thing. If it works, we can put it into Google Cloud Functions.

Step 1

Below the Code Editor, is the Google Cloud Shell command window. Click in it.

First, make sure you are in the correct folder.

cd ~/converter-cloud-function

Step 2

Use NPM to install all the dependencies that are listed in the package.json file.

npm install

Step 3

Start the program (recall that the program will listen on port 8081).

npm start

If the program works, the output should be similar to what is shown below.

If it doesn't work, you'll have to debug it.

Step 4

To see the program running, click the Web Preview button in the toolbar of Cloud Shell. Then, select Change port and Port 8081.

The program should be displayed in a new browser tab.

Step 5

First, let's test the Web page.

Enter 100 in the text box and click the Fahrenheit button. The result should be 212. Enter 212 in the text box and click the Celsius button. The result should be 100.

Step 6

Now let's test the API.

In the URL of your browser, after devshell.appspost.com add the following route.

/api/conversions/to-fahrenheit/100

It should return a JSON object as shown below.

Now try:

/api/conversions/to-celsius/32

It should return:

Step 7

To stop the program, go back to the browser tab with Cloud Shell. Click in the command window and press Ctrl+C on your keyboard.

The hard part is over! You just need to create one more JavaScript file and run one command to deploy your app to Cloud Functions.

Cloud Functions expects to see a file called index.js. And inside that file, you must export a function. The function you export is the Cloud Function. In this example, the function you are going to export is your Express application.

Recall that your Express application is defined in the file app.js.

Step 1

Right-click your converter-cloud-function folder in the code editor and add a new file called index.js. Paste the code below in that file.

var app = require('./app');

function App(req,res) {
    if (!req.url) {
        req.url = '/';
        req.path = '/';
    }
    return app(req,res);
}

var converter = App;

module.exports = {
    converter
};

Let's explain this code.

The first line imports the app module. This is your Express application.

The function App() is a bit of a Cloud Functions hack. It turns out that the Cloud Function won't work if there isn't a slash (/) at the end of the request. This function just makes sure that if there is no slash, one is added. Notice, the App() function in the end just returns our app module imported on the first line.

The line that reads: var converter = App; just sets the name of our function. The name of the Cloud Function must match the name of the function that is exported.

In the last line, the converter function is exported.

Step 2

It's time to deploy. Enter the following command in Cloud Shell. It will take a minute or two for this command to complete.

gcloud beta functions deploy converter --trigger-http 

Step 3

When the deployment command completes, go back to the browser tab that hosts the GCP Management Console.

If the Cloud Functions page is not currently displayed, then from the Products and Services menu select Cloud Functions.

Your converter function should be listed and hopefully has a green check indicating it is working. You might have to press the Refresh button to see the function, and/or the green check mark.

Step 4

Click the converter function to open its details. Then, select the Trigger tab.

Step 5

Click the URL to see if it works. Try to do a couple conversions.

You may or may not have noticed the cheat in the code. We will fix it now.

Step 1

Go back to the Code Editor and open the index.js file in the routes folder.

Step 2

Look at the post handler and the URL variable. The code is shown below:

The cheat is that the code is pointing to a Cloud Function that I created, not your Cloud Function. Change this line so the URL points to the function you just deployed.

Then, redeploy the function just as you did in the last section.

Step 3

Make sure your program still works.

This lab was provided by ROI Training.

Check out some related courses:

Please click the link below and give us some feedback on this lab. You will automatically be entered to win a new Google Home.

Feedback and Drawing Form