Polyglot with open source, Part 1: An introduction to IBM Cloud Functions

This two-part series demonstrates how easy it is to use different programming languages with Apache OpenWhisk. Here you learn how to write an application using IBM Cloud Functions and Watson natural language processing (NLP) that translates every new English document that is inserted into a database into Spanish.

This article will serve as an introduction to serverless computing using IBM Cloud Functions, which is based on Apache OpenWhisk. In this article, you create IBM Cloud Functions that listen to changes in the database and translate new records as they are added, using the natural processing services on IBM Cloud. For this example, I use IBM Cloudant as the database, which is the managed version of Apache CouchDB on the IBM Cloud. After completing this exercise, you should understand the main concepts behind serverless and be able to host your code on IBM Cloud Functions.

Prerequisites

  1. Create an IBM Cloud account.
  2. Install an IBM Cloud command line interface (CLI).
  3. Install the cloud functions CLI plug-in.

Estimated time

Allow about 20 minutes to read this article and try out the example.

Create your first IBM Cloud function

Before you create your first function, let’s quickly go over some terminology. This is useful if you’ve never worked with Apache OpenWhisk or IBM Cloud Functions or just a great refresher for seasoned developers.

  • An action is your code that will run on the serverless platform.
  • A trigger listens to the changes outside of your function.
  • A rule binds a trigger to an action. When a trigger is fired, the corresponding action can be triggered (or executed).
  • A package bundles actions, triggers, and rules into a module. IBM Cloud Functions comes with some built in packages. In this article, I use whisk.system/cloudantpackage.

Let’s begin by using the CLI to create your first function.

  1. Log into your IBM Cloud account using the CLI:

     » ibmcloud login
     API endpoint: https://cloud.ibm.com
     Region: us-south
     Email> upkar.ibm.watson.5@gmail.com
     Password>
     Authenticating...
     OK
     Targeted account Upkar Lidder's Account (a086ce7d00df4423ab024b123b587e76)
     API endpoint:      https://cloud.ibm.com
     Region:            us-south
     User:              upkar.ibm.watson.5@gmail.com
     Account:           Upkar Lidder's Account (xxxxxx)
     Resource group:    No resource group targeted, use 'ibmcloud target -g RESOURCE_GROUP'
     CF API endpoint:
     Org:
     Space:
    
  2. Target your Cloud Foundry instance so that you are in the right space and organization:

     » ibmcloud target --cf
     Targeted Cloud Foundry (https://api.us-south.cf.cloud.ibm.com)
     Targeted org upkar.ibm.watson.5@gmail.com
     Targeted space dev
     API endpoint:      https://cloud.ibm.com
     Region:            us-south
     User:              upkar.ibm.watson.5@gmail.com
     Account:           Upkar Lidder's Account (xxxxxx)
     Resource group:    No resource group targeted, use 'ibmcloud target -g RESOURCE_GROUP'
     CF API endpoint:   https://api.us-south.cf.cloud.ibm.com (API version: 2.142.0)
     Org:               upkar.ibm.watson.5@gmail.com
     Space:             dev
    
  3. Let’s also target the default resource group:

     » ibmcloud target -g Default
     Targeted resource group Default
     API endpoint:      https://cloud.ibm.com
     Region:            us-south
     User:              upkar.ibm.watson.5@gmail.com
     Account:           Upkar Lidder's Account (a086ce7d00df4423ab024b123b587e76)
     Resource group:    Default
     CF API endpoint:   https://api.us-south.cf.cloud.ibm.com (API version: 2.142.0)
     Org:               upkar.ibm.watson.5@gmail.com
     Space:             dev
    
  4. You’re now ready to create your first function. In keeping with tradition, create a Hello World function by creating a file named index.js and add the following:

     function main(args) {
     if (args && args.name) {
        return { greeting: `hello ${args.name}` };
     } else {
        return { greeting: `hello world` };
     }
     }
    

    That’s it! This is a simple function and a greeting of hello name is returned if there is a name in the args. If there isn’t, a greeting of hello world is returned.

  5. Now, let’s push this function to the IBM Cloud:

     » ibmcloud fn action create hello-action index.js
     ok: created action hello-action
    

    Great! You just created an IBM Cloud function. But how do you know if it’s working?

  6. To invoke your new function, use the -r flag to tell the CLI to wait for the results to come back:

     » ibmcloud fn action invoke hello-action -r
     {
         "greeting": "hello world"
     }
    

    Look at that! You got your greeting back. Let’s pass in a param using the -p flag:

     » ibmcloud fn action invoke hello-action -r -p name "upkar lidder"
     {
         "greeting": "hello upkar lidder"
     }
    
  7. Create a new service for Cloudant by logging into your IBM Cloud account. Click on catalog and search for Cloudant (you should find this under the Databases category).

    Cloudant database

    Next, select the Lite plan to create an instance of the Cloudant service.

    Lite plan from Cloudant database

    You need to select Use only IAM as the available authentication methods at the bottom of the screen to enable the create button. Then click on the Create resource button.

    Use only IAM athentication method

    The services take a couple of minutes to provision. You can see the status on the Resources page.

    Cloudant-q7 provision in progress

    Once the service has been provisioned, navigate to the main landing page of the service to get the credentials. You can find existing credentials or create new credentials under the Service credentials tab. Make note of the service name, Cloudant-q7, in the screen below to bind this service to your function.

    Cloudant-q7

  8. Launch Cloudant from the Manage tab and create a new database called textdb.

    Launch Cloudanat database textdb Database

  9. Now you need to bind whisk.system/cloudant to your namespace, resulting in a new package that is identical to the whisk.system/cloudant package. You can then use the actions and feeds in your new package to listen to changes in Cloudant in the Cloudant instance you just created in the step above.

     » ibmcloud fn package bind /whisk.system/cloudant my-cloudant-package
     ok: created binding my-cloudant-package
    

    The steps above resulted in a new package called my-cloudant-package in your namespace. You can view the details of this package by using the ibmcloud fn package command. As you can see, the package exposes a lot of actions. You should also take note of the feed listed as the last item.

     » ibmcloud fn package get my-cloudant-package --summary                                                          
     package /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package: Returns a result based on parameters apihost and bluemixServiceName
        (parameters: *apihost, *bluemixServiceName)
      action /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/delete-attachment: Delete document attachment from database
        (parameters: attachmentname, dbname, docid, docrev, params)
      action /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/update-attachment: Update document attachment in database
        (parameters: attachment, attachmentname, contenttype, dbname, docid, docrev, params)
      action /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/read-attachment: Read document attachment from database
        (parameters: attachmentname, dbname, docid, params)
      action /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/create-attachment: Create document attachment in database
        (parameters: attachment, attachmentname, contenttype, dbname, docid, docrev, params)
      action /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/read-changes-feed: Read Cloudant database changes feed (non-continuous)
        (parameters: dbname, params)
      action /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/delete-query-index: Delete index from design document
        (parameters: dbname, docid, indexname, params)
     ...
     ...
     feed   /upkar.ibm.watson.5@gmail.com_dev/my-cloudant-package/changes: Database change feed
        (parameters: dbname, filter, iamApiKey, iamUrl, query_params)
    
  10. Bind your Cloudant database instance with the package you just created to ensure that the Cloudant credentials are made available to the package:

     » ibmcloud fn service bind cloudantnosqldb my-cloudant-package --instance Cloudant-q7
     Credentials 'Service credentials-1' from 'cloudantnosqldb' service instance 'Cloudant-q7' bound to 'my-cloudant-package'.
    
  11. Next, create a trigger to listen to the feed. A success status should appear in the response, as shown below:

    “`

» ibmcloud fn trigger create db_changes_trigger --feed my-cloudant-package/changes -p dbname textdb
ok: invoked /_/my-cloudant-package/changes with id 9a530d262ba94982930d262ba9098223
{
    "activationId": "9a530d262ba94982930d262ba9098223",
    ...
    ...
    "response": {
        "result": {
            "status": "success"
        },
        "size": 20,
        "status": "success",
        "success": true
    },
    "start": 1576613689501,
    "subject": "upkar.ibm.watson.5@gmail.com",
    "version": "0.0.165"
}
ok: created trigger db_changes_trigger
```

In a nutshell, you are asking the `ibmcloud fn` CLI to create a trigger called **db_changes_trigger** that will listen to the *upkar-cloudant-package/changes* feed for changes in the textdb database. Now, check that the trigger was created. It should look something like this:

```
» ibmcloud fn trigger list
triggers
/upkar.ibm.watson.5@gmail.com_dev/db_changes_trigger                   private
```
  1. Perfect! It’s now time to see if the trigger is fired when you make changes to textdb. In order to see any output, you need to create a rule that connects the trigger to your simple action that you created in the beginning.

      » ibmcloud fn rule create textdb_change_rule db_changes_trigger hello-action
      ok: created rule textdb_change_rule
    

    In order to see any output, you can tail the functions’ logs by using the activation poll feature as follows:

      » ibmcloud fn activation
      poll
      Enter Ctrl-c to exit.
      Polling for activation logs
    

    You should see some output if you create a new document or change an existing document:

    Output created from creating or changing documents

     Activation: 'hello-action' (20fe527c16fa43e4be527c16fa73e463)
     []
     Activation: 'db_changes_trigger' (741001c34e7d45909001c34e7d959028)
     [
         "{\"statusCode\":0,\"success\":true,\"activationId\":\"20fe527c16fa43e4be527c16fa73e463\",\"rule\":\"upkar.ibm.watson.5@gmail.com_dev/textdb_change_rule\",\"action\":\"upkar.ibm.watson.5@gmail.com_dev/hello-action\"}"
     ]
     Activation: 'hello-action' (784454fb665748e08454fb665778e0fe)
     []
     Activation: 'db_changes_trigger' (7d107c0938564f31907c0938566f3146)
     [
         "{\"statusCode\":0,\"success\":true,\"activationId\":\"784454fb665748e08454fb665778e0fe\",\"rule\":\"upkar.ibm.watson.5@gmail.com_dev/textdb_change_rule\",\"action\":\"upkar.ibm.watson.5@gmail.com_dev/hello-action\"}"
     ]
    

    The above code reveals that you inserted two documents and the trigger was fired twice. Since the trigger is connected to your action with a rule, your action, hello-action, was called twice. The action itself just returns a greeting at this point. In part two of this series, you will change the action to process the document that was inserted into the database.

Summary

Congratulations! You successfully created a simple Hello World function on IBM Cloud Functions. You also learned how to use an existing package and listen to database changes by creating a trigger on a feed. You even created a rule that connected the trigger to your action! Now that you have all the pieces in place, you are ready for part two, where you will get a chance to create a second action that uses Watson NLP to convert the message to Spanish! While you wait, try a few serverless or NLP hands-on examples to build on your knowledge.