What’s new web actions?
A little over a month ago, I introduced web actions for creating serverless HTTP handlers with OpenWhisk.
Web actions allow one to run code in response to HTTP events, without deploying or managing their own servers. Web actions are built into the OpenWhisk core, and hence require no extra tooling or configuration (e.g., no need for an “API gateway” for the common case). This provides a much more convenient way to build front-end or back-end logic (e.g., user interface or REST API).
Web actions were first featured as an experimental API, and thanks to user feedback from our growing Slack community, we made several enhancements and graduated web actions to the core API. I will review the new features with a brief example.
Here is a Node.js function which takes a given msg
argument and uses it as a response in the HTTP body:
function main(args) {
return { body: args.msg }
}
Save this function to a file called msg.js
to turn it into a web action, using a new wsk
CLI flag --web
:
$ wsk action create hi msg.js --web yes
The action is now accessible from the new web
API path:
$ curl https://{APIHOST}/api/v1/web/{ACTION NAME}
For IBM Cloud Functions, the APIHOST
is openwhisk.ng.bluemix.net
. The “action name” is the fully qualified name of the action which must include the namespace, the package name (or default
if the action is not in a named package), and the name of the action. For convenience you can retrieve the full URL with the CLI:
$ wsk action get hi --url
https://openwhisk.ng.bluemix.net/api/v1/web/rabbah_demos/default/hi
You can plug the resultant URL into your browser, add a query parameter, and see the response. Here’s mine as an example:
https://openwhisk.ng.bluemix.net/api/v1/web/rabbah_demos/default/hi?msg=hello medium reader
The result of a web action, like any other OpenWhisk action must be a JSON object (e.g., { body: "hello." }
). However web actions impose a schema on the response. It must include a body
property which contains the HTTP response content. Optionally, response headers
and a statusCode
may be included. When the former is omitted, the content-type is automatically inferred. The status code is 200 unless specified explicitly.
Web actions receive query parameters as first class parameters in the action; for instance, the action directly accesses args.msg
in the example above. This also applies to HTTP body entities for content-type application/json
or application/x-www-form-urlencoded
. If a query parameter also appears in the body, the latter supersedes.
It is also possible to access the “raw” HTTP query string and body entity. This means web actions can receive content-types other than JSON objects. A raw web action receives the request query parameters and body via two properties of the input argument: __ow_query
and __ow_body
. The former is a string as in __ow_query = "msg=Hello&name=Reader"
, and the latter is either a plain string, or a base64 encoded string when the content-type representation is binary data. An example of a raw web action that receives a JSON object (which is considered a binary data type) as __ow_body
and converts it to String follows:
function main(args) {
let json = new Buffer(args.__ow_body, 'base64') # base64 decode
return { body: json.toString('utf-8') } # json as string
}
A raw web action must be declared as such when created or updated. Say the example function above is saved in a file called raw.js
:
$ wsk action update hi raw.js --web raw$ curl https://openwhisk.ng.bluemix.net/api/v1/web/rabbah_demos/default/hi -H "Content-Type: application/json" -X POST -d '{"msg":"Hello"}'
{"msg":"Hello"}
Note that the response content-type is “text” not JSON; you can confirm this by inspecting the headers (use curl -v
), or by using one of several web action-name extensions that automatically set the content-type for the response based on the value of the extension. Specifically, repeating the HTTP request with a .text
suffix on the action name as in hi.text
will automatically set the response header Content-Type: text/plain; charset=UTF-8
. The API provides 5 common extensions: .html
, .http
,.json
, .text
and .svg
, with .http
as the default if no extension is specified.
All but the .http
extension allow you to project a specific field from the action response. So for the raw.js
example, the value to project as “text” is body
. Here is the actual curl command (with the extension and the projected value in bold font):
$ curl https://openwhisk.ng.bluemix.net/api/v1/web/rabbah_demos/default/hi.text/body -H "Content-Type: application/json" -X POST -d '{"msg":"Hello"}'
The extensions are convenient for returning common formats, allowing you to eschew setting headers explicitly. The default projection for .text
is /text
(e.g., return { text: “some string” }
) and may be omitted. For .html
it is /html
and for .svg
it is /svg
. There is no default projection for .json
, and the .http
does not support this feature.
So in summary:
- Web actions may be created using the
wsk
CLI via--web yes
to enable,--web no
to disable, and--web raw
for raw web actions. - Raw web actions receive
__ow_body
and__ow_query
as uninterpreted entities. In addition, all web actions receive headers, unmatched paths, and the HTTP methods respectively as__ow_headers
,__ow_path
,__ow_method
. - The
.http
extension may be omitted as it is the default. For added convenience, a new.svg
extension now exists for servingimage/svg+xml
content. - Lastly, we added support for all the HTTP methods, so web actions allow you to handle
PATCH
,HEAD
, andOPTIONS
methods as well as the common REST verbsPOST
,PUT
,GET
, andDELETE
.
More information on web actions is available on GitHub. The features described in this article are available to try with IBM Cloud Functions.
Do you have feedback for us? Join us on Slack and be part of the evolution of OpenWhisk.