Local Development with Cloud Functions for Node.js using Visual Studio Code

1. Overview

Google Cloud Functions is an event-driven serverless compute platform. Cloud Functions allows you to write your code without worrying about provisioning resources or scaling to handle changing requirements.

Cloud Functions written in Javascript execute in a Node.js environment on Google Cloud Platform. You can run your Cloud Function in any standard Node.js runtime to enable portability and local testing.

Walkthrough

In this codelab, you will create a Cloud Function for Node.js that reports whether a specified temperature is acceptable or too hot. You will create, test, and debug your Cloud Function using Visual Studio Code on your local machine. Lastly, you'll deploy your function to Google Cloud Platform.

What you'll learn

  • Functions Framework for Node.js.
  • Create and test a HTTP Cloud Function locally.
  • Debug a HTTP Function from your local machine.
  • Deploy a HTTP Function from your local machine.

2. Setup and Requirements

Prerequisites

Costs

Although this codelab only requires 1 invocation of a deployed Cloud Function, you should still reference the Cloud Functions API pricing information to understand how billing works.

While many Google APIs can be used without fees, use of Google Cloud Platform (i.e. its products & APIs) is not free. You will need an active billing account to use Cloud Functions. Keep in mind that certain Google Cloud Platform (GCP) products feature an "Always Free" tier for which you have to exceed in order to incur billing. For the purposes of the codelab, each Cloud Functions invocation counts against that free tier. As long as you stay within its limits in aggregate (within each month), you should not incur any charges.

3. Install the Functions Framework for Node.js

The Functions Framework for Node.js is an open source FaaS (Function as a Service) framework for writing portable Node.js functions that is brought to you by the Google Cloud Functions team.

The Functions Framework lets you write lightweight functions that run in many different environments, including:

  • Google Cloud Functions
  • Your local development machine
  • Cloud Run and Cloud Run on GKE
  • Knative-based environments

Create a new node.js app.

npm init

While accepting defaults, make sure to use index.js as the entry point for your app.

Now install the Functions Framework for Node.js.

npm install @google-cloud/functions-framework

Open your package.json. Verify that you see the functions framework listed as a dependency as shown in the example below.

"dependencies": {
   "@google-cloud/functions-framework": "^1.7.1"
 }

The Functions Framework has now been successfully installed. You are now ready to create your Cloud Function.

4. Create and test a HTTP Cloud Function locally

Create a local Cloud Function

In this section, you will create and test a HTTP Function that responds to HTTP requests.

Create a new file called index.js in the same directory as your package.json file.

Add the following:

exports.validateTemperature = async (req, res) => {
 try {
   if (req.body.temp < 100) {
     res.status(200).send("Temperature OK");
   } else {
     res.status(200).send("Too hot");
   }
 } catch (error) {
   //return an error
   console.log("got error: ", error);
   res.status(500).send(error);
 }
};

You are now ready to test the function.

Test function in Visual Studio Code

From this point on, this codelab uses the integrated terminal within Visual Studio Code.

In Visual Studio Code, open a terminal window.

Run the following command:

node node_modules/@google-cloud/functions-framework --target=validateTemperature

This command starts a local server that is ready to call the validateTemperature function when the server receives an HTTP request.

You should see the following output in your terminal window:

Serving function...
Function: validateTemperature
URL: http://localhost:8080/

Create a second terminal window within VS Code by clicking the New Terminal plus icon in the Terminal window pane. You will switch between these two terminal windows: the first for serving the function and the second for calling the function using curl.

bceb65f366d837ae.png

You can switch between terminal windows by using the drop down. If a terminal window is currently serving a function, the drop down list refers to it as node. Otherwise it is referred to zsh (or the shell you are using).

In the second terminal window, run the following command to send a temperature payload of 50 to the local server serving the validateTemperature function.

curl -X POST http://localhost:8080 -H "Content-Type:application/json"  -d '{"temp":"50"}'

You should receive the following response from the cloud function:

Temperature OK

In the second terminal window, test the function again by sending a "too high" temperature payload as shown below:

curl -X POST http://localhost:8080 -H "Content-Type:application/json"  -d '{"temp":"120"}'

You should receive the following response from the cloud function:

Too hot

Lastly, test the function by calling it with a missing payload.

curl -X POST http://localhost:8080

You should receive the following response from the cloud function:

Too hot

Ideally, the function should not return "too hot" if no temperature is provided. You have discovered a bug in the code.

Make sure to stop your function from running by pressing Ctrl + C in the first terminal window serving your function.

5. Debug a HTTP Function from your local machine

Open the Command Palette in Visual Studio Code. If you're on a Mac, use Cmd + Shift + P. If you're on Windows, use Ctrl + Shift + P.

Type auto attach in the Command Palette and pick the top item in the list.

601e542b4ec9f6f9.png

For this codelab, choose Only With Flag as shown in the image below:

b9e6b762d150e62b.png

Now reload the terminal window you used in VS Code to serve your function by hovering-over the warning icon that appears on the far right side.

Click Relaunch Terminal.

37b61e3fb546fc76.png

From the reloaded terminal window, re-run the functions framework to serve your function using the following command:

node --inspect node_modules/.bin/functions-framework --target=validateTemperature

where the --inspect flag tells Node.js to listen for a debugging client. For more info, please see the Node documentation on debugging.

Note that you are using node_modules/.bin/functions-framework instead of node_modules/@google-cloud/functions-framework. You need to use the automatically symlinked executable in /node_modules/.bin for using the inspect mode.

This time you should see an orange status bar in VS Code indicating that the debugger is attached.

Set a breakpoint at line 3 by clicking inside the margin to the left of the line number.

2fbb4d5916e1dbfa.png

The breakpoint icon should illuminate bright red, indicating this line of code is accessible by the debugger.

846e6c5993cc87f9.png

In the second terminal window, hit the breakpoint by running the following curl command.

curl -X POST http://localhost:8080 

You will see a yellow highlight appear over line 3. This highlight indicates that this line is the current statement being evaluated by the debugger.

206c7ed1eb189e90.png

Mouse-over the temp variable to verify that its contents are undefined, since the request did not provide a temperature payload.

97979025f4bf2842.png

Click the step-over icon to execute the next statement.

You will see the current statement jump to the else portion of the if statement.

cf0e8ce7e0388f98.png

For this demo, you can assume that the specification requires all requests to send a temperature reading. In the unlikely event a temperature reading is not provided, the function should throw an exception.

Click the Disconnect button to disconnect the debugger.

1070d059775ad769.png

In your first terminal window, stop serving your function from running by pressing Ctrl + C.

Update your function to add an if statement to throw an exception if temperature is undefined as shown below:

exports.validateTemperature = async (req, res) => {

 try {

   // add this if statement below line #2
   if (!req.body.temp) {
     throw "Temperature is undefined";
   }

 ...

In your first terminal window, start running your cloud function again by running the following command without the –inspect flag to avoid attaching the debugger.

node node_modules/@google-cloud/functions-framework --target=validateTemperature

Verify that an exception is thrown by running the following command in your second terminal window:

curl -X POST http://localhost:8080 

You should see the following output returned from your request:

Temperature is undefined

In your first terminal window, you'll also see the error logged by your function.

Serving function...
Function: validateTemperature
URL: http://localhost:8080/
got error:  Temperature is undefined

You can now stop running your function by pressing Ctrl + C in your first terminal window.

6. Deploy a HTTP Function from your local machine to Google Cloud

Now that you've created, tested, and debugged a Cloud Function on your local machine, you are ready to deploy it to Google Cloud.

Verify you are using the project you created in Step 2 locally by running the following command:

gcloud config get-value project

If the project you specified in Step 2 is not the active configuration, run the following command:

gcloud config set project <project-name-created-step-2>

In any terminal window, run the following command:

gcloud functions deploy validateTemperature --trigger-http --runtime nodejs12 --allow-unauthenticated

where the parameters are explained as follows:

  • deploy validateTemperature - the gcloud subcommand for deploying a Cloud Function with the name validateTemperature with an entry point named validateTemperature
  • --trigger-http - the triggering event type
  • --runtime nodejs12 - the targeted runtime for this function
  • --allow-unauthenticated - allows public access to call the function

You will be prompted to enable the Cloud Functions APIs. Type y to enable the APIs.

API [cloudfunctions.googleapis.com] not enabled on project 
[1057316433766]. Would you like to enable and retry (this will take a 
few minutes)? (y/N)? y 

Once deployment is completed, you will see the following in the output:

Deploying function (may take a while - up to 2 minutes)...done. 
availableMemoryMb: 256
buildId: <your-build-id>
entryPoint: validateTemperature
httpsTrigger:
  url: https://<your-region-and-project>.cloudfunctions.net/validateTemperature
...

In your terminal window, use curl to call this public endpoint.

curl -X POST https://<your-region-and-project>.cloudfunctions.net/validateTemperature -H "Content-Type:application/json"  -d '{"temp":"50"}'

and confirm that your cloud function has been deployed successfully by verifying the appropriate response.

Temperature OK

7. Clean up

To avoid inadvertent charges, e.g. this Cloud Function is inadvertently invoked more times than your monthly Cloud Function invokement allocation in the free tier, you can either delete the Cloud Function or delete the project you created in Step 2.

To delete the Cloud Function, go to the Cloud Function Cloud Console at https://console.cloud.google.com/functions/ Make sure the project you created in step 2 is the currently selected project.

Select the validateTemperature function you deployed in Step 6. Then hit Delete.

4dada486485a935a.png

If you choose to delete the entire project, you can go to https://console.cloud.google.com/cloud-resource-manager, select the project you created in Step 2, and choose Delete. If you delete the project, you'll need to change projects in your Cloud SDK. You can view the list of all available projects by running gcloud projects list.

8. Congratulations!

Congratulations for completing the codelab. You can learn more about how Cloud Functions supports the Node.js runtime and how local debugging works with Cloud Functions.

What we've covered

  • Functions Framework for Node.js.
  • Create and test a HTTP Cloud Function locally.
  • Debug a HTTP Function from your local machine.
  • Deploy a HTTP Function from your local machine.