Contents


Write runnable and deployable code for the IBM Cloud Functions platform

How to write code that you can run and deploy in the developerWorks sandbox

Comments

Interactive code: When you see Run at the top of a code sample, you can run the code, check the results, make changes, and run it again. When you see Deploy, you can deploy the code into the developerWorks IBM Cloud account.

One of the great things about the developerWorks sandbox is that you can run your code in the browser or deploy it to IBM® Bluemix®. Your deployed code is an action on the IBM® Cloud Functions platform. However, the Cloud Functions platform requires your code to support a particular interface before you can deploy it. This tutorial explains the rules and requirements to make everything work.

In this tutorial, you'll see how to write JavaScript or Java™ code that can be run in the browser or deployed as a Cloud Functions action via a developerWorks sandbox. The sandboxes in this tutorial help you build, test, and work with your code directly. A detailed explanation of the code follows each sandbox.

In this tutorial, you'll:

  1. See developerWorks sandboxes containing runnable and deployable code for both JavaScript and Java
  2. Learn how to make any piece of code deployable
  3. Learn how to make any piece of deployable code runnable

About serverless actions

In a nutshell, the IBM Cloud Functions platform requires that your code take a JSON object as its only input and return a JSON object as its output. Working with JSON is easy if you're using JavaScript. If you're using Java, you need to use Google's gson library to work with JSON objects. All the details of working with JSON and gson are covered in this tutorial. Finally, be aware that building the input JSON object sent to your code and interpreting its JSON output is the job of the developer invoking your action.

To learn how to invoke your code once you've deployed it, see the developerWorks tutorial Invoking actions on the IBM Cloud Functions platform.

Note: The Cloud Functions platform is built on Apache OpenWhisk technology. As you use the platform, you'll occasionally see the OpenWhisk name. The two use the same concepts and terminology, so you can mentally replace "OpenWhisk" with "Cloud Functions."

A simple runnable and deployable JavaScript sample

A Cloud Functions-compatible Hello World is just about the simplest piece of code that's both runnable and deployable.

Show result

Testing the code

Before we discuss what makes this code runnable and deployable, let's test it. Click the Run button above. Depending on the value you passed in for the name field, you should see something like this:

{ greeting: 'Hello, Susan' }

Now click the Deploy button. The sandbox deploys the code to the Cloud Functions platform as a new action and displays its URL:

https://openwhisk.ng.bluemix.net/api/v1/web/devworkssandbox_pub/270003KAD5/0-1001.json

Note: the URL that's generated is unique for you, so what you'll see will be different from the examples here.

Now let's invoke the code that we just deployed. In the sandbox below, replace [URL] with the URL generated by the Deploy button above. (Obviously, you can change the name as well if you like.) When you press the Run button below, the code in the sandbox below invokes the action you created when you deployed the code above.

Show result

The output from this sandbox should look familiar:

{ greeting: 'Hello, Susan' }

Although the results are the same, the contents of the two sandboxes above are very different. The first contains code that is runnable in the browser or deployable to the Cloud Functions platform. The second contains code that invokes an action on the platform. You can replace the url in the second sandbox with any URL of any public action, add the JSON data required by that action, and use this code to invoke it.

Now let's move on to the details of actually writing code that is runnable and deployable.

Writing deployable JavaScript code

The basic structure of a Cloud Functions action written in JavaScript looks like this:

function main(params) {
  // Do something useful with the parameters here
  var output = {};
  // Put anything you want your action to return into the output object
  return output;
}

When a JavaScript action is invoked, the Cloud Functions environment looks for a method named main(). If there is no method by that name, the invocation fails. In the code in the sandbox above, only the main() function is required to deploy the code. For this example, pass the code a JSON object containing a field named name, and everything works.

Making the JavaScript code runnable

Making the code runnable requires defining the behavior that should happen when someone, well, tries to run this file. In our case, that means creating a default JSON object and passing it to the main() method. These lines of code make it runnable:

var defaultParameters = {'name': 'Susan'};
 
if (require.main === module) 
  console.log(main(defaultParameters));

The appropriately named variable defaultParameters defines a JSON object containing the default parameters used when you click the Run button. The next line is more complicated. If the statement require.main === module evaluates to true, that means this file is being run directly, as opposed to being run via require(). If that's the case, the node.js runtime calls the main() method. (For the full details on this technique, the Node.js documentation discusses accessing the main() module.)

Calling the main() method inside a console.log() call means that whatever results come back from the main() method are written to the screen. This works for the simple JSON object in the example, but often you'll have a more complicated object. That's when you'll want to use the JSON.stringify() method:

if (require.main === module) 
  console.log(JSON.stringify(main(defaultParameters), null, 2));

The JSON.stringify() method is a convenience function that formats JSON data. The first parameter here is the actual call to main(), the second parameter is null (we could pass in a function to manipulate the JSON data, but we won't), and the third parameter indents the data by 2 spaces. Formatting the code with JSON.stringify() is worth the trouble when you work with an action that returns a complex JSON object with lots of useful information.

One more thing: You don't have to declare the defaultParameters object. You could put the JSON data inside the call to main():

if (require.main === module) 
  console.log(main({'name': 'Susan'}));

This isn't practical if you're passing in a complicated JSON object, but it works.

Creating asynchronous actions

The Cloud Functions platform enables asynchronous actions by allowing JavaScript code to return a Promise instead of a basic JSON object. In this example, the code calls the Watson Language Translator service. The service takes a string and translates it based on two codes that indicate the source language and the target language.

Asynchronous actions are necessary because you don't want the main() method to end before your code gets the results back from the Watson service. Returning a Promise lets the client get the results whenever they arrive from the service. This technique is useful with any long-running task, such as database access or file I/O. (For more information about Promises, including a sandbox that lets you write your own, see Ted Neward's tutorial on the new features of ECMAScript 6.)

Show result

Writing deployable, asynchronous JavaScript code

The basic structure of an asynchronous action looks like this:

function main(params) {
  return new Promise(function (resolve, reject) {
    invokeSomething(params, function(error, results) {
      if (error)
        reject(error);
      else
        resolve(results);
    });
  });
}

In the code in the sandbox above, the call to the Watson Language Translator service takes place inside the Promise. At some point, the service returns an Error object and a JSON object containing the results. If anything went wrong (the Error object is not null), the reject() method returns the Error object. Otherwise, the resolve() method returns the JSON object returned by the service.

Note: In the sandbox above, the username and password values can be blank when you invoke this code from this page. To invoke this code once you've deployed it, make the following changes to the defaultParameters object:

  1. Fill in the username, password, and url fields with your Bluemix credentials for the Language Translator service.
  2. Set the use_unauthenticated field to false.

See the overview of the Language Translator service for more information about how to create an instance of the Translator service and generate credentials for it.

Making the asynchronous JavaScript code runnable

Making the code runnable is a little more complicated because you need to handle the Promise object. As before, you define a JSON object with default parameters, but after you call main() you use the then() and catch() methods:

const defaultParameters = {
  'textToTranslate' : 'That that is not confusing is amazing.',
  'username'        : '',
  'password'        : '',
  'url'             : 'https://sandbox-watson-proxy.mybluemix.net/language-translator/api',
  'use_unauthenticated' : true
}

if (require.main === module)
  main(defaultParameters)
    .then((results) => console.log(JSON.stringify(results, null, 2)))
    .catch((error) => console.log(error.message));

The then() method handles whatever was returned by the resolve() call in the Promise. In this case, that is the JSON object that contains the translation of the text. The catch() method handles the error case, dealing with the Error object returned by the reject()method.

For complete details on asynchronous actions, see the article Creating and invoking Cloud Functions actions and scroll down to the section "Creating asynchronous actions."

A runnable and deployable Java sample

Let's move on to Java now. Here's a simple example that's runnable and deployable:

Show result

Testing the code

As we did with the JavaScript samples above, let's test the code before we talk about what makes it runnable and deployable. Click the Run button above. Depending on the value you passed in for the name field, you should see something like this:

{'greeting': 'Hello, Susan'}

Now click the Deploy button. The sandbox deploys the code to the Cloud Functions platform as a new action and displays its URL:

https://openwhisk.ng.bluemix.net/api/v1/web/devworkssandbox_pub/270003KAD5/0-1003.json

(Again, the URL you'll see is unique to you.)

Now we'll invoke the code that we just deployed. In the sandbox below, replace [URL] with the URL generated by the Deploy button above. When you press the Run button, this code invokes the action you created when you deployed the code in the Java sandbox above.

Show result

The output from this sandbox should look familiar:

{
  "greeting": "Hello, Susan"
}

Writing deployable Java code

The Cloud Functions platform requires your Java class to have this basic structure:

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

// Other imports here

public class MyClass {
  public static JsonObject main(JsonObject args) {
    // Parse the args JsonObject so we can work with it
    
    // Use the Google gson library to create a JsonObject with the 
    // appropriate output
    JsonObject returnObject = ...;
    return returnObject;
  }
}

Note: Be aware that the developerWorks sandbox doesn't support the Java package statement.

The main() method has a different signature than the one you've used in the past. Because Cloud Functions actions require a JsonObject as input and output, you need to use this signature instead. The Cloud Functions environment has the venerable Google gson library installed, so use that to work with JSON data here. Working with JSON in JavaScript is easier because JSON is built in to the language. With Java, you have to go through gson to process the input and output data.

Making the Java code runnable

The example in the first Java sandbox above is both deployable and runnable. The lines that make this code runnable create some default data and overload the main() method by creating a new one with the traditional signature:

private static String data = "{'name': 'Susan'}";

public static void main(String[] args) {
  JsonObject jsonArgs = new JsonParser().parse(data).getAsJsonObject();
  main(jsonArgs);
}

The main(String[]) method creates a JsonObject from the default data and calls the main(JsonObject) method. Simple as that.

Bonus: A more complex runnable and deployable Java sample

As a bonus, here is the Java version of the earlier sample that uses the Watson Language Translator service. Notice that the Watson Java SDK lets you use the Java collection classes and various Java objects (TranslationResult and Translation, for example) as a wrapper for the underlying JSON. That makes the code look much more like a regular Java program. When it's time to return JSON data, a single line of code converts the results from the service into a JSON structure.

Show result

As you can see, this sample uses the techniques we covered earlier so that you can both run and deploy this code. (The Java code is simpler than the node.js version because Java is synchronous. The Java runtime waits patiently until the Language Translator service returns a result.)

To invoke this code once you've deployed it, make the following changes to the data object:

  1. Fill in the username, password, and endpoint fields with your Bluemix credentials for the Language Translator service.
  2. Set the skip_authentication field to false.

Summary

We've covered how to write JavaScript and Java code that anyone can run and deploy in the developerWorks sandbox.

We encourage you to open your own free Bluemix account and deploy the code in this tutorial. It's a great way to learn more, and the wsk tool and the Bluemix console give you a complete suite of debugging capabilities.

Enjoy the world of serverless computing!


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, Open source
ArticleID=1047411
ArticleTitle=Write runnable and deployable code for the IBM Cloud Functions platform
publish-date=07102017