Friday, January 18, 2019

FaaS tutorial 2: Set up Google Cloud Function

Now that we have deployed an app in FaaS tutorial 1: Start with Firebase and prepare the ground, time to spice up 🌶️ our basic app to add some back-end stuff.

What about defining a REST API to add a new record to the database. We'll use HTTP triggered functions. There are different kind of triggers for different use cases, we dig into that in the next post.

Let's start out tutorial, as always step by steps 👣!

Step 1: init function

For your project to use Google Cloud Functions (GCF), use firebase cli to configure it. Simply run the command:
$ firebase init functions

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /Users/corinne/workspace/test-crud2


=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Select a default Firebase project for this directory: test-83c1a (test)
i  Using project test-83c1a (test)

=== Functions Setup

A functions directory will be created in your project with a Node.js
package pre-configured. Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? JavaScript
? Do you want to use ESLint to catch probable bugs and enforce style? No
✔  Wrote functions/package.json
✔  Wrote functions/index.js
✔  Wrote functions/.gitignore
? Do you want to install dependencies with npm now? Yes
Below the ascii art 🎨 Firebase gets chatty and tells you all about it's doing.
Once you've selected a firebase project (select the one we created in tutorial 1 with the firestore setup), you use default options (JavaScript, no ESLint).

Note: By default, GCF runs on node6, if you want to enable node8, in your /functions/package.json add the following json at root level:
"engines": {
    "node": "8"
  }
You will need node8 for the rest of the tutorial as we use async instead of Promises syntax.
Firebase has created a default package with an initial GCF bootstrap in functions/index.js.

Step 2: HelloWorld

Go to functions/index.js and uncomment the helloWorld function
exports.helloWorld = functions.https.onCall((request, response) => {
 response.send("Hello from Firebase!");
});
This is a basic helloWorld function, we'll use just to get use to deploying functions.

Step 3: deploy

Again, use firebase cli and type the command:
$ firebase deploy --only functions
✔  functions[helloWorld(us-central1)]: Successful update operation. 
✔  Deploy complete!

Please note that it can take up to 30 seconds for your updated functions to propagate.
Project Console: https://console.firebase.google.com/project/test-83c1a/overview
Note you call also deploy just our functions by adding firebase deploy --only functions:myFunctionName.
If you go to the Firebase console and then in the function tab, you will find the URL where your function is available.



Step 3: try it

Since it's an HTTP triggered function, let's trying with curl:
$ curl https://us-central1-test-83c1a.cloudfunctions.net/helloWorld
Hello from Firebase!
You've deployed and tried your first cloud function. 🎉🎉🎉
Let's now try to fulfil the same use-case as per tutorial 1: We want an HTTP triggered function than insert 2 fields in a database collection.

Step 4: onRequest function to insert in DB

  • In function/index.js add the function below:
    const admin = require('firebase-admin');
    admin.initializeApp(); // [2]
    
    exports.insertOnRequest = functions.https.onRequest(async (req, res) => {
      const field1 = req.query.field1; // [2] 
      const field2 = req.query.field2;
      const writeResult = await admin.firestore().collection('items').add({field1: field1, field2: field2}); // [3]
      res.json({result: `Message with ID: ${writeResult.id} added.`}); // [4]
    });
    

    • [1]: import the Firebase Admin SDK to access the Firestore database and initialize with default values.
    • [2]: extract data from query param.
    • [3]: add the new message into the Firestore Database using the Firebase Admin SDK.
    • [4]: send back the id of the newly inserted record.
  • Deploy it with firebase deploy --only functions. This will redeploy both functions.
  • Test it by curling:
    $ curl https://us-central1-test-83c1a.cloudfunctions.net/insertOnRequest\?field1\=test1\&field2\=test2
    {"result":"Message with ID: b5Nw8U3wraQhRqJ0vMER added."}
    
Wow! Even better, you've deployed a cloud function that does something 🎉🎉🎉

Note thatif your use-case is to call a cloud function from your UI, you can onCall CGF. Some of the boiler plate around security is taken care for you. Let's try to add an onCall function!

Step 5: onCall function to insert in DB

  • In function/index.js add the function below:
    exports.insertOnCall = functions.https.onCall(async (data, context) => {
      console.log(`insertOnCall::Add to database ${JSON.stringify(data)}`);
      const {field1, field2} = data;
      await admin.firestore().collection('items').add({field1, field2});
    });
    
  • Deploy it with firebase deploy --only functions. This will redeploy both functions.
  • Test it in your UI code. In tutorial 1, step5 we defined a Create component in src/component/index.js, let's revisit the onSumit method:
    onSubmit = (e) => {
        e.preventDefault();
        // insert by calling cloud function
        const insertDB = firebase.functions().httpsCallable('insertOnCall'); // [1]
        insertDB(this.state).then((result) => { // [2]
          console.log(`::Result is ${JSON.stringify(result)}`);
          this.setState({
            field1: '',
            field2: '',
          });
          this.props.history.push("/")
        }).catch((error) => {
          console.error("Error adding document: ", error);
        });
      };
    

    In [1] we passed the name of the function to retrieve a reference, we simply call this function in [2] with json object containing all the fields we need.

Where to go from here?

In this tutorial, you've get acquainted with google function in its most simple form: http triggered. To go further into learning how to code GCF, the best way is to look at existing code: the firebase/functions-samples on GitHub is the perfect place to explore.
In next tutorials we'll explore the different use-cases that fit best a cloud function.

Stay tuned!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.