Deploying Express.js apps to OpenWhisk (Part 1)

Ad-hoc approach

In this article I will show you how to deploy Express.js applications to OpenWhisk, with minimal modification. The Part 2 generalizes the process described below.

Getting started

For the purpose on this article, let’s first create a new Express 4.x application. If you want to use your own app (be sure it’s using the 4.x api. In particular, app.listen(..) must not be in the main file), just skip this step.

$ npm install express-generator -g
$ express --view=pug myexpressapp
$ cd myexpressapp
$ npm install

To check it’s working, start the application by typing the command npm start and load http://localhost:3000 in a browser.

Auto-generated Express app

Paths consideration

The generated Express application expects resources to be installed in the domain root folder, but by default OpenWhisk web actions are served from a sub-directory. Luckily only one file needs to be changed, views/layout.pug:

doctype html
html
head
title= title
if baseurl
base(href=baseurl)
link(rel='stylesheet', href='stylesheets/style.css')
body
block content

Installing the OpenWhisk web action

The next step is to create the OpenWhisk web action that will invoke the Express app. This is a generic action that can be reused across all Express apps. It is available here and self-explanatory. Just copy it into your root directory and add following dependency:

$ npm install supertest --dev

Deploying

Our application is now ready to be deployed to OpenWhisk. For this step, I assume you have the OpenWhisk CLI installed and set up. If you happen to have a Bluemix account (no credit cards required), the setup is much easier.

Let’s create a zip action that can then be deployed:

$ zip -r app.zip .
$ wsk action update express app.zip --kind nodejs:6 --web raw -p baseurl <yourbaseurl>

This command says to update an action called express and to put it in the default package. --web raw makes the action web accessible with raw handling and -p baseurl <yourbaseurl> sets the parameter baseurl to your base url.

For instance, I use this command on Bluemix:

$ wsk action update express app.zip --kind nodejs:6 --web raw -p baseurl https://openwhisk.ng.bluemix.net/api/v1/web/villard@us.ibm.com_dev/default/express/

To load this web action, go to https://openwhisk.ng.bluemix.net/api/v1/web/villard@us.ibm.com_dev/default/express

Optional: deploying static assets elsewhere

Due to several OpenWhisk limits, it’s better to host large static assets somewhere else. Here I’ll use Surge because it’s really easy to use.

First, install the tool with npm and run the surge command in the directory containing your static assets, in this case public.

$ npm install -global surge
$ cd public
$ surge

If this is your first time running, you will need to enter your email and password to register a new account.

Deploying static assets on Surge

We then need to tell our Express app to fetch the static assets from Surge. The OpenWhisk web action expects the argument named staticbaseurl so let’s use it in our views/layout.pug template:

doctype html
html
head
title= title
base(href=baseurl)
link(rel='stylesheet',
href=`${staticbaseurl || ''}stylesheets/style.css')
body
block content

Let’s redeployed our application, but this time using the static assets hosted on Surge:

$ zip -r app.zip . --exclude=public/*
$ wsk action update express app.zip --kind nodejs:6 \
--web raw \
-p baseurl https://openwhisk.ng.bluemix.net/api/v1/web/villard@us.ibm.com_dev/default/express/ \
-p staticbaseurl https://openwhisk-expressjs-demo.surge.sh/

Don’t forget to substitute the baseurl and staticbaseurl values by your own values. Reload the action, open the HTML source code to see that the stylesheets being loaded from Surge.

Conclusion and teaser

With little effort, we created a new Express.js app and deployed it on a serverless cloud platform that automatically and reasonably scales for you.

In the second part of this post I’ll go through the steps of deploying a real express application composed of three separate Express apps secured by Auth0 and JWT.

Thanks for your feedback in advance.