Web Actions: Serverless Web Apps with OpenWhisk

If you’re a developer of web applications and you haven’t tried going “serverless” yet, you’re missing out! Whether you try Amazon Lambda or IBM’s OpenWhisk powered by Apache OpenWhisk, you’ll surely be impressed by its simplicity, compared to standing up and operating a Node.js Express app for example.

Let me give you a quick tour— I hope this inspires you to try out OpenWhisk. I will create a service that generates QR codes: you type in some text and you get back a corresponding QR code. This example will use a new OpenWhisk feature called web actions.

The application consists of a static HTML page that offers a text field for visitors to type in and submit the text to generate and display the QR code. For the QR generation, I will adapt an OpenWhisk Java action introduced in a previous article. Below, I show an abbreviated version of the code, highlighting the salient bits. You can read all the source code on GitHub.

Some background: OpenWhisk actions are “functions” which receive a JSON object as an input argument and must produce a JSON object as a result.
public static JsonObject main(JsonObject args) {
    // read 'text' property from input
String text = args.getAsJsonPrimitive("text").getAsString();
    // generate the QR code and base64 encode the result
String output = generateCodeAndBase64EncodeIt(text);

// the action result as an HTTP response
JsonObject response = new JsonObject();
    // set content-type header for the response
JsonObject headers = new JsonObject();
headers.addProperty("content-type", "image/png");
response.add("headers", headers);

// set the body for the response
response.addProperty("body", output);
    return response;

The QR generator method accepts a JSON object as input which contains a text property to encode. The response from the method is a JSON object with two fields: headers which in this case is a single HTTP header defining the content-type as image/png, and a body containing a base64 encoded string of the image.

What makes this code special is that you can just deploy it to run in a serverless runtime in seconds, and it will be web/browser accessible. I’m going to use the OpenWhisk command line interface wsk to create this web app. The build steps are the same as in the blog post linked earlier but I will add --annotation web-export true to make the code accessible from a web browser.

$ wsk action create qr/generate builds/libs/qr-1.0.jar \
--main qr.Generate \
--annotation web-export true

The web-export feature is a new OpenWhisk addition to make the actions available from a web browser: you can type the URL of the qr action and get an image in return. Try it: click this link and you’ll see the QR code shown above. The link passed a query parameters ?text=... to the action which is used to generate the QR code.

Now, to create a friendlier interface to input text, I’ll use another action that allows a visitor to the page to enter text in a form field instead of passing parameters in the URL. When the visitor finishes typing, the QR code is rendered. The action code that generates the HTML is available on GitHub. It uses Bootstrap and jQuery to style the page and make it dynamic. Below is a screenshot of what it looks like — you may try it yourself here.

With serverless programming, you don’t deploy servers, only your code. The platform manages the resources to run your code and provides elastic scaling as needed. The OpenWhisk pricing model is such that you will pay for compute time and memory that your actions use. Using the serverless cost calculator, the estimated cost to generate 1M codes with OpenWhisk is a whopping $0.21, ignoring the free tier.

By making your actions web accessible, you pay for running the actions that serve your web content (for example), but if your application is not getting traffic, you incur no cost.

Web actions allow you to write serverless HTTP handlers, and can provide a gentle migration path from existing services to serverless. I describe them in more detail here.

Web actions are served from a URL that is structured as follows: https://{APIHOST}/api/v1/experimental/web/{QUALIFIED ACTION NAME}.{EXT}. The API host is openwhisk.ng.bluemix.net for Bluemix. The fully qualified name of an action consists of three parts: the namespace, the package name, and the action name. An example is guest/qr/ui. The last part of the URI is the extension which is typically .html or .http although other values are permitted.

A convenient way to determine the full URL of a web action is to construct it dynamically as done in this example.

If you’ve enjoyed reading this and want to learn more, you can check out the project on GitHub or join us on Slack.