How-tos

Cloud Functions Package Design and Best Practices

Share this post:

IBM Cloud Functions and installable packages

Whether they’re JARs, libs, Gems, or modules, successful programming languages provide an ability to share and re-use code. IBM Cloud Functions is no different—it enables developer productivity through installable packages.

The companion app that is linked at the end of this “Reviewing IBM Cloud services, resources, and usage” article provides several new packages—notably for SQL Query and Cognos Dashboard Embedded. Having created these packages, I can now consider the question: “What makes a good package?

Delivery

Arguably the most important aspect of a package utility is easily finding and installing code. IBM Cloud Functions uses wskdeploy to define which artifacts are installed—from Actions to Sequences and even managed APIs. To include other packages as dependencies, developers need only add a statement in their manifest.

dependencies:
cloud-object-storage:
location: github.com/ibm-functions/package-cloud-object-storage/runtimes/nodejs

As you can see from the location property, the package is hosted directly from GitHub. So your code, documentation, and delivery can all be done from one place. To make finding packages easier, add the topic openwhisk-packages to your repository.

Composition

Packages deliver functionality. You can leverage package artifacts—such as an Action—by chaining them together into a Sequence. For example, a common use case for SQL Query is to run a SQL job and retrieve the results from IBM Cloud Object Storage. After calling the SQL Query API, my package simply sets up the required inputs for Cloud Object Storage. The official IBM Cloud Object Storage package does the actual work and retrieves the data. After the data is retrieved, my result-set action in this Sequence returns the CSV file containing the results.

sequences:
sql-job-resultset:
actions: sql-query,cloud-object-storage/object-read,result-set

Using this pattern, I can compose application behavior by referencing the Actions and even Sequences from other packages. I might not even need to write “code” in some cases.

In addition to packages that interact with various services, you can also find templates, which are small solutions consisting of Actions, Triggers, and Sequences that often build upon available packages to solve a problem. Learn more about Templates here.

Functionality

Providing functionality from a package is a balance. Provide too much, and the package becomes more of an app. Provide too little, and developers simply write their own solutions.

To support the use case of obtaining a result from Cloud Object Storage, I found that SQL Query made most of the data I needed available; but, it required just a bit more tweaking to get to the correct Cloud Object Storage input format.

So my package wraps the SQL Query API in just enough code to make it callable as a Function and adds just enough information to make it compatible with Cloud Object Storage. Here you can see the small amount of work I do to add the endpoint, bucket, and key properties using the resultset_location provided by SQL Query. By doing this, I enrich the SQL Query response with information likely needed by other packages—in this case Cloud Object Storage.

const [endpoint, bucket, ...rest] = response.resultset_location.substring(6).split('/');
let key = rest.join('/');

const cos: any = await this.getCosKey(endpoint, this.options.auth, bucket, `${key}/part`);
key = cos.ListBucketResult.Contents[0].Key[0];

return { …response, endpoint, bucket, key };

Ultimately, service offering managers can’t conceive all the ways people will combine them. So little packages such as this provide convenient bridges between them.

My package also provides an API so that services like Cognos Dashboard Embedded can download the result from the web. This may be doing a bit more than is necessary, but I felt the use case was common enough to make it package-worthy.

Customization

A benefit to using Cloud Functions is that if you don’t like them, you can change them. I write most of my Functions code in TypeScript. But the compiler options I was using made the final code hard to read. Changing the config to es2017 helped produce more readable native JavaScript. Now, developers can install my package and then make it their own by adjusting the JavaScript code within the Cloud Functions user interface. Keep this in mind as you create Docker Functions or code that uses other packaging techniques such as NPM or webpack.

With a little bit of thought and code, you can create packages that make IBM Cloud even more approachable to a growing audience of Functions developers.

IBM Offering Manager

Belinda Vennam

IBM Cloud Developer Advocate

More How-tos stories
October 19, 2018

Part 1: Build Messaging Solutions with Apache Kafka or Event Streams for IBM Cloud

As part of the iterative approach described in the main introduction blog of this series, the first step is to building messaging solutions is to identify the use case requirements and quantify these requirements as much as possible in terms of Apache Kafka and Event Streams.

Continue reading

October 18, 2018

Mount iSCSI Block Storage on VMware ESXi 6.5U2

It seems like pretty much everyone is using VMware ESXi virtualization nowadays. In this article, I'll cover how to mount IBM Cloud Block Storages onto this popular hypervisor using the iSCSI protocol.

Continue reading

October 18, 2018

Journey to Cloud – Moving On-Premise Mobile Foundation Apps to IBM Cloud

IBM MobileFirst Platform Foundation powers many on-premise customers in more than 50 countries, delivering the best-of-the-best apps and serving a large number of users. IBM Cloud Mobile Foundation Service offers all the same capabilities available in on-premise MobileFirst Foundation, with the additional benefits of fully managed service with instant deployment and scale-out option.

Continue reading