Creating web actions
IBM Cloud® Functions is deprecated. Existing Functions entities such as actions, triggers, or sequences will continue to run, but as of 28 December 2023, you can’t create new Functions entities. Existing Functions entities are supported until October 2024. Any Functions entities that still exist on that date will be deleted. For more information, see Deprecation overview.
When you create an IBM Cloud® Functions web action, the result is a URL that can be used to trigger the action from any web app.
The IBM Cloud® Functions web actions API endpoint changed. To align with other customer services, a new functions.appdomain.cloud
API endpoint is available for web actions. The API endpoint functions.cloud.ibm.com
is
still active, but now returns response data as content type text/plain
instead of text/html
. Other content types are not changing. Migrate your web actions to use the new API endpoint. The previous endpoints are deprecated
and will be deactivated at some point.
Why use web actions instead of standard actions?
- Run web actions anonymously
-
Web action activations are associated with the user that created the action, rather than the caller of the action. Usually, for API calls to apps such as GitHub, you would include a username and token with the API call for either a specific user or a functional ID. When you use a web action, those kinds of credentials are not required. A web action is accessible through a REST interface without the need for credentials.
-
Though you are not required to use credentials with web actions, you can implement your own authentication and authorization, or OAuth flow. To configure a web action with credentials, see Securing web actions.
- Use any type of HTTP request
-
By default, actions accept only
POST
requests, but web actions can be invoked through any of these HTTP methods:GET
,POST
,PUT
,PATCH
, andDELETE
, as well asHEAD
andOPTIONS
. - Trigger a web action from anywhere
-
When you create an IBM Cloud® Functions web action, you generate a URL to invoke that action from any web-based app. Actions that are not web actions require authentication and must respond with a JSON object. To get the URL of a web action, you can run the
action get
command and include the--url
flag. For example,ibmcloud fn action get <action_name> --url
. -
A web action API path can be used with cURL,
wget
, or even be entered directly in your browser. A web action can be invoked by using a URL that is structured as follows,https://<apihost>/api/v1/web/<namespace_ID>/<packageName>/<actionName>.<ext>
. - Create fewer Cloud Functions entities
-
Because you can invoke a web action from anywhere, you are not required to create other Cloud Functions entities like triggers or rules.
- Allows non-2xx return codes
-
Cloud Functions web actions can return non-2xx codes, allowing your code to be more flexible and allow for retries.
How do web actions work?
Web actions can be invoked without authentication and can be used to implement HTTP handlers that respond with headers
, statusCode
, and body
content of different types.
Web actions must return a JSON object. However, the controller treats a web action differently if its result includes one or more of the properties as top-level JSON properties.
Packaging code for web actions
Cloud Functions actions can be web-enabled by including the --web true
flag in the action create
command.
You can create a web action from multiple app files by packaging them as a .zip archive. You can also create a web action by using Docker images.
- To learn how to package your code for actions, see Preparing apps for actions.
- To see more examples of how you can create actions, see Creating actions.
Available features of web actions
Web actions support the following features:
Content extensions
You can specify a content type for your web action response by adding an extension to the action name in the URI. The following content types are supported: .json
, .http
, .html
, .svg
, or
.text
. For example, an action <namespace_ID>/demo/hello
is referenced as <namespace_ID>/demo/hello.json
to receive a .json
response. \n For content type .json
,
the full return object is returned, similar to {resOne: "some text", resTwo: 42}
. \n For .html
, .svg
, or .text
, the content of the property that is called body
is
returned, similar to .http
. If you want to use one response object for multiple content types, you can add the corresponding properties into the return object and remove the body
property. The return object is then
similar to {html: "<p>The html response</p>", text: "text response"}
. \n If no content type is specified, the .http
extension is assumed, and the content of the property that is called
body
is returned, for example, {body: "the return message"}
.
Query and body parameters as input
The action receives query parameters as well as parameters in the request body. The precedence order for merging parameters is: package parameters, action parameters, query parameter, and body parameters. Each of these parameters can override
any previous values if overlap occurs. As an example, /demo/hello.http?name=Jane
can pass the argument {name: "Jane"}
to the action.
Form data
In addition to the standard application/json
, web actions can receive URL encoded form data application/x-www-form-urlencoded data
as input.
Activations that use multiple HTTP verbs
A web action can be invoked through any of these HTTP methods: GET
, POST
, PUT
, PATCH
, and DELETE
, as well as HEAD
and OPTIONS
.
Non-JSON body and raw HTTP entity handling
A web action can accept an HTTP request body other than a JSON object, and can elect to always receive such values as opaque values (plain text when not binary file, or base64 encoded string otherwise).
Creating a web action
To create a web action:
-
Save the following JavaScript code as
hello.js
.function main({name}) { var msg = 'You did not tell me who you are.'; if (name) { msg = `Hello, ${name}!` } return {body: `<html><body><h3>${msg}</h3></body></html>`} }
-
Create the
demo
package. The package name isdefault
unless explicitly specified.ibmcloud fn package create demo
-
Create the
hello
action. In this example, thepackageName/actionName
aredemo/hello
. Replace the<filepath>
variable with the file path of yourhello.js
file and set the--web
flag totrue
.ibmcloud fn action create demo/hello <filepath>/hello.js --web true
-
Invoke or test the
hello
web action without any parameters. Replace the<apihost>
and<namespace_ID>
variables. Example<apihost>
:https://us-south.functions.appdomain.cloud
.For IAM-enabled namespaces, replace the
<namespace_ID>
variable with the namespace ID. To get the ID, runibmcloud fn namespace get <namespace_name> --properties
. The namespace name is not valid.a. You can test the web action by either:
-
Opening a URL by using the following structure
https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
in your browser. -
Testing the action by using a cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
-
Testing the action by using a
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
b. The action code returns the following dictionary.
{body: `<html><body><h3>${msg}</h3></body></html>`}
You can also test the action by returning just the
body
property by using the following command:curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.html/body
Example output
Since the
<name>
parameter was not specified, the following message is returned.<html><body><h3>You did not tell me who you are.</h3></body></html>
-
-
Now try defining the
<name>
parameter. Test the action with a<name>
parameter by either:-
Opening
https://<apihost>/api/v1/web/<namespace_ID>/demo/hello?name=Jane
in your browser. -
Testing the action by using a cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello?name=Jane
-
Testing the action by using a
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello?name=Jane
Example output
<html><body><h3>Hello, Jane!</h3></body></html>
-
Next steps, try adding the URL for your hello
web action to your web app and test it there.
Web action JSON properties
The default Content-Type
for an HTTP response is application/json
, and the body can be any allowed JSON value. If your Content-Type
is not application/json
, you must specify a Content-Type
in the headers
of your action code.
If the result size limit for actions is reached, the response fails. If you know that your action result is larger than 5 MB, then set up an object store.
JSON property | Description |
---|---|
headers |
A JSON object in which the keys are header names and the values are string, number, or boolean values. To send multiple values for a single header, the header's value is a JSON array of the multiple values. No headers are set by default. |
statusCode |
A valid HTTP status code. If body content is present, the default is 200 OK . If no body content is present, the default is 204 No Content . |
body |
A string that is either plain text, a JSON object or array, or a base64 encoded string for binary data. The body is considered empty if it is null , the empty string "" , or undefined. The default is
an empty body. |
The controller passes any action-specified headers, status code, or body to the HTTP client that terminates the request or response. If the Content-Type
header
is not declared in the action result's headers
, the body is interpreted as application/json
for non-string values and text/html
otherwise. If the Content-Type
header is defined, the controller
determines whether the response is binary data or plain text and decodes the string by using a base64 decoder as needed. If the body isn't decoded correctly, an error is returned to the client.
The owner of the web action owns all the activations records, and incurs the cost of running the action in the system regardless of how the action was invoked.
Protected parameters
Action parameters are protected and can be changed only by updating your action. Parameters are automatically finalized to enable web actions.
ibmcloud fn action create /<namespace_ID>/demo/hello hello.js --parameter name Jane --web true
The result of these changes is that the name
is bound to Jane
and cannot be overridden by query or body parameters because of the final annotation. This design secures the action against query or body parameters
that try to change this value whether by accident or intentionally.
Performing an HTTP redirect by using a web action
You might use this feature in a web application to redirect a user to the new version of your site.
Before you begin
Create the demo
package and hello
web action by completing the steps in Creating a web action.
This example web action redirects your browser to the Cloud Functions dashboard. To create a web action that performs an HTTP redirect:
-
Save the code as
hello.js
.function main() { return { headers: { location: 'https://cloud.ibm.com/openwhisk/' }, statusCode: 302 } }
-
Update your
hello
web action with the new version for yourhello.js
code. Replace<filepath>
with the file path of yourhello.js
file.ibmcloud fn action update demo/hello <filepath>/hello.js --web true
-
Test the
hello
web action. Replace the<apihost>
and<namespace_ID>
variables. You can test the web action by using one of the following methods.-
Opening the URL
https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
in your browser. -
Running the following cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
-
Running the following
wget
command,wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
-
Returning an image by using a web action
Images that are returned through web actions are required to be base64 encoded strings. You might use this feature in a web application to return the image of a country flag based on user locale.
Before you begin
Create the demo
package and hello
web action by completing the steps in Creating a web action.
To create a web action that returns an image/png
:
-
Save the code as
hello.js
. Replace<base64_encoded_string>
with a base64 encoded string from an image file.function main() { let png = '<base64_encoded_string>'; return { headers: { 'Content-Type': 'image/png' }, statusCode: 200, body: png }; }
-
Update your
hello
web action with the new version for yourhello.js
code. Replace<filepath>
with the file path of yourhello.js
file.ibmcloud fn action update demo/hello <filepath>/hello.js --web true
-
Test the action in your browser or by using a cURL command. Replace the
<apihost>
and<namespace_ID>
variables. You can test the web action by either:-
Opening the URL
https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
in your browser. -
Running the following cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
-
Running the following
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
-
Returning JSON by using a web action
You might use this feature in a web application to return a JSON object of user IP information.
Before you begin
Create the demo
package and hello
web action by completing the steps in Creating a web action.
To create a web action that returns application/json
:
-
Save the code as
hello.js
.function main(params) { return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: params }; }
-
Update your
hello
web action with the new version for yourhello.js
code. Replace<filepath>
with the file path of yourhello.js
file.ibmcloud fn action update demo/hello <filepath>/hello.js --web true
-
Test the action in your browser or by using a cURL command. Replace the
<apihost>
and<namespace_ID>
variables. You can test the web action by using one of the following methods.-
Opening the URL
https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
in your browser. -
Running the following cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
-
Running the following
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello
Example output
{ "__ow_headers": { "accept": "*/*", "accept-encoding": "gzip", "cdn-loop": "cloudflare", "cf-connecting-ip": "XX.XXX.XXX.XXX", "cf-ipcountry": "US", "cf-ray": "4d9f3e442a86cf28-IAD", "cf-visitor": "{\"scheme\":\"https\"}", "host": "<apihost>", "user-agent": "curl/7.54.0", "x-forwarded-for": "XX.XXX.XX.XXX, XX.XXX.XX.XXX", "x-forwarded-host": "<apihost>", "x-forwarded-port": "443", "x-forwarded-proto": "https", "x-global-k8fdic-transaction-id": "11fd03071bd0841d3a00f52354ab880f", "x-real-ip": "XXX.XX.XX.XX", "x-request-id": "11fd03071bd0841d3a00f52354ab880f" }, "__ow_method": "get", "__ow_path": "" }
-
HTTP context
All web actions, when invoked, receive HTTP request details as input parameters to the action argument.
HTTP parameter | Type | Description |
---|---|---|
__ow_method |
String | The HTTP method of the request. |
__ow_headers |
Map string to string | The request headers. |
__ow_path |
String | The unmatched path of the request (matching stops once the action extension is consumed). |
__ow_user |
String | The namespace_ID that identifies the Cloud Functions-authenticated subject. |
__ow_body |
String | The request body entity, as a base64 encoded string when content is a binary file, or plain string otherwise. |
__ow_query |
String | The query parameters from the request as an unparsed string. |
A request cannot override any of the named __ow_
parameters. Doing so, results in a failed request with status equal to 400 Bad Request.
The __ow_user
is only present when the web action is annotated to require authentication and allows a web action to implement its own
authorization policy. The __ow_query
is available only when a web action elects to handle the "raw" HTTP request. The __ow_query
is a string that contains the query
parameters that are parsed from the URI (separated by &
). The __ow_body
property is present in either raw HTTP requests, or when the HTTP request entity is not a JSON object or form data. Otherwise, web actions
receive query and body parameters as first class properties in the action argument. Body parameters take precedence over query parameters, which in turn take precedence over action and package parameters.
HTTPS Endpoint support
Supported SSL protocols: TLS 1.2, TLS 1.3 (draft version 18)
Altering the response content of web action
You can alter the response content of a web action to return different content types by using Content extensions.
Before you begin
Create the demo
package and hello
web action by completing the steps in Creating a web action.
To alter the response of a web action:
-
Save the following code as
hello.js
.function main(params) { return { response: params }; }
-
Update your
hello
web action with the new version of yourhello.js
code. Replace<filepath>
with the file path of yourhello.js
file.ibmcloud fn action update demo/hello <filepath>/hello.js --web true
-
Test the action in your browser or by using a cURL command. Replace the
<apihost>
and<namespace_ID>
variables.a. Return JSON by either:
* Opening `https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json` in your web browser. * Running the following cURL command. ```bash {: pre} curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json ``` * Running the following `wget` command. ```bash {: pre} wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json ```
Example output
{ "response": { "__ow_method": "get", "__ow_headers": { "accept": "*/*", "connection": "close", "host": "172.17.0.1", "user-agent": "curl/7.43.0" }, "__ow_path": "" } }
b. Test the action by using a query parameter. You can test the action by either:
* Running the following cURL command. ```bash {: pre} curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane ``` * Running the following `wget` command. ```bash {: pre} wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane ```
Example output
{ "response": { "name": "Jane", "__ow_method": "get", "__ow_headers": { "accept": "*/*", "connection": "close", "host": "172.17.0.1", "user-agent": "curl/7.43.0" }, "__ow_path": "" } }
c. You can also test the web action by using form data. You can test the web action by using one of the following methods.{: #form_data} * Running the following cURL command.
```bash {: pre} curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json -d "name":"Jane" ``` * Running the following `wget` command. ```bash {: pre} wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json -d "name":"Jane" ```
Example output
{ "response": { "name": "Jane", "__ow_method": "post", "__ow_headers": { "accept": "*/*", "connection": "close", "content-length": "10", "content-type": "application/x-www-form-urlencoded", "host": "172.17.0.1", "user-agent": "curl/7.43.0" }, "__ow_path": "" } }
d. You can specify a JSON object by running the following command. You can test the web action by using one of the following methods.
* Running the following cURL command. ```bash {: pre} curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json -H 'Content-Type: application/json' -d '{"name":"Jane"}' ``` * Running the following `wget` command. ```bash {: pre} wget https://<apihost>/api/v1/web/{namespace_ID/demo/hello.json -H 'Content-Type: application/json' -d '{"name":"Jane"}' ```
Example output
{ "response": { "name": "Jane", "__ow_method": "post", "__ow_headers": { "accept": "*/*", "connection": "close", "content-length": "15", "content-type": "application/json", "host": "172.17.0.1", "user-agent": "curl/7.43.0" }, "__ow_path": "" } }
e. You can also return the
name
value as text by either:* Running the following cURL command. ```bash {: pre} curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.text/response/name?name=Jane ``` * Running the following `wget` command. ```bash {: pre} wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.text/response/name?name=Jane ```
Example output
Jane
In standard actions, query parameters, form data, and JSON object body entities are all treated as dictionaries, and their values are directly accessible as action input properties. This behavior is not the case for web actions, which handle HTTP request entities, or when the web action receives an entity that is not a JSON object.
f. You can set the
Content-Type
by using one of the following methods.* Running the following cURL command. ```bash {: pre} curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json -H 'Content-Type: text/plain' -d "Jane" ``` * Running the following `wget` command. ```sh {: pre} wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json -H 'Content-Type: text/plain' -d "Jane" ```
Example output
{ "response": { "__ow_method": "post", "__ow_headers": { "accept": "*/*", "connection": "close", "content-length": "4", "content-type": "text/plain", "host": "172.17.0.1", "user-agent": "curl/7.43.0" }, "__ow_path": "", "__ow_body": "Jane" } }
Securing web actions
By default, anyone can invoke a web action by using the invocation URL. You can secure your web action by using the require-whisk-auth
web action annotation.
Before you begin
Create the demo
package and hello
web action by completing the steps in Creating a web action.
You can set the require-whisk-auth
annotation by either:
-
Setting the
require-whisk-auth
annotation totrue
. When therequire-whisk-auth
annotation is set totrue
, the web action authenticates the invocation requests Basic Authorization credentials against the web action owner's whisk auth key. When set to a number or a case-sensitive string, the web action's invocation request must include theX-Require-Whisk-Auth
header set to this same number or case-sensitive string. Secured web actions return the messageNot Authorized
when credential validation fails. -
Allowing the
require-whisk-auth
annotation to be set automatically by using the--web-secure
flag. When the--web-secure
flag is set totrue
, a random number is generated as therequire-whisk-auth
annotation value. When set tofalse
, therequire-whisk-auth
annotation is removed. When set to any other value, that value is used as therequire-whisk-auth
annotation value.
Creating a secure web action
Start by creating a web action with the --web secure
set to true
.
-
Save the following JavaScript code as
hello.js
.function main({name}) { var msg = 'You did not tell me who you are.'; if (name) { msg = `Hello, ${name}!` } return {body: `<html><body><h3>${msg}</h3></body></html>`} }
-
Update your
hello
web action with the new version of yourhello.js
code and set the--web secure
option totrue
.ibmcloud fn action update demo/hello /<filepath>/hello.js --web true --web-secure true
-
Get the
hello
web action to view the randomly generatedrequire-whisk-auth
value.ibmcloud fn action get demo/hello
Example output
The
require-whisk-auth
value was set to7819991076995522
.{ "namespace": "<namespace_ID>/demo", "name": "hello", "version": "0.0.34", "exec": { "kind": "nodejs:10", "binary": false }, "annotations": [ { "key": "web-export", "value": true }, { "key": "raw-http", "value": false }, { "key": "final", "value": true }, { "key": "require-whisk-auth", "value": 7819991076995522 }, { "key": "exec", "value": "nodejs:10" } ], "limits": { "timeout": 60000, "memory": 256, "logs": 10, "concurrency": 1 }, "publish": false }
Testing a secure web action with randomly generated value of X-Require-Whisk-Auth
Test the hello
web action and provide the randomly generated X-Require-Whisk-Auth
value. Replace the <apihost>
and <namespace_ID>
values. Replace the <my-secret>
value with the randomly generated number that you found in step 3 of Creating a secure web action.
You can test the web action by using one of the following methods.
-
Testing the web action by using a cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane -X GET -H "X-Require-Whisk-Auth: <my-secret>"
-
Testing the web action by using a
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane -X GET -H "X-Require-Whisk-Auth: <my-secret>"
Example output
{
"body": "<html><body><h3>Hello, Jane!</h3></body></html>"
}
Testing a secure web action with custom value of X-Require-Whisk-Auth
To secure your web action with a custom value, update your hello
web action with your own require-whisk-auth
value. Then, try testing your web action by specifying the X-Require-Whisk-Auth
value during
invocation.
-
Set a
require-whisk-auth
value where<my-secret>
is your case-sensitive authentication token.ibmcloud fn action update demo/hello /<filepath>/hello.js --web true --annotation require-whisk-auth <mysecret>
-
Test the web action and include your
<my-secret>
value. You can test the web action by using one of the following methods.-
Testing the web action by using a cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane -X GET -H "X-Require-Whisk-Auth: <my-secret>"
-
Testing the action by using a
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane -X GET -H "X-Require-Whisk-Auth: <my-secret>"
-
Testing to see if your web action is secure
Test the hello
web action without setting the X-Require-Whisk-Auth
parameter to verify that authentication is required. Using the actions that you created in the previous sections, this test results in an error.
You can get the URL of your web action by running ibmcloud fn action get hello --url
. You can use the URL to test the web action by using one of the following methods.
-
Testing the web action by using a cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane
-
Testing the web action by using a
wget
command.wget https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane
Example output
{
"code": "4c4423556547f6ac764ee192d4ed27a6",
"error": "Authentication is possible but has failed or not yet been provided."
}
The invocation fails because the X-Require-Whisk-Auth
value was not provided.
Raw HTTP handling
A web action can elect to interpret and process an incoming HTTP body directly, without the promotion of a JSON object to first class properties available to the web action input (for example, args.name
versus parsing args.__ow_query
).
This process is done through a raw-http
annotation. Using the same example that was shown earlier, but now as a "raw" HTTP web action that receives name
,
both as a query parameter, and as JSON value in the HTTP request body.
curl https://<apihost>/api/v1/web/<namespace_ID>/demo/hello.json?name=Jane -X POST -H "Content-Type: application/json" -d '{"name":"Jane"}'
Example output
{
"response": {
"__ow_method": "post",
"__ow_query": "name=Jane",
"__ow_body": "eyJuYW1lIjoiSmFuZSJ9",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"content-length": "15",
"content-type": "application/json",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
Cloud Functions uses the Akka HTTP framework to determine which content types are binary files and which are plain text.
Enabling raw HTTP handling
You can create a raw HTTP web action by setting the --web
to raw
.
ibmcloud fn action create demo/hello /<filepath>/hello.js --web raw
Decoding binary body content from Base64
When raw HTTP content is processed, the __ow_body
content is encoded in Base64 when the request Content-Type
is the binary type. The following functions demonstrate how to decode the body content in Node, Python,
and Swift.
-
Save the sample code in your preferred language to a file called
decode.<ext>
. Replace<ext>
with the file extension of the sample code of your preferred language.Node
function main(args) { decoded = new Buffer(args.__ow_body, 'base64').toString('utf-8') return {body: decoded} }
Python
def main(args): try: decoded = args['__ow_body'].decode('base64').strip() return {"body": decoded} except: return {"body": "Could not decode body from Base64."}
Swift
extension String { func base64Decode() -> String? { guard let data = Data(base64Encoded: self) else { return nil } return String(data: data, encoding: .utf8) } } func main(args: [String:Any]) -> [String:Any] { if let body = args["__ow_body"] as? String { if let decoded = body.base64Decode() { return [ "body" : decoded ] } } return ["body": "Could not decode body from Base64."] }
-
Create a raw HTTP web action with the sample code by running the following command. In this example, the Node function is saved as
decode.js
. Replace the file path with the file path of yourdecode
file and update the file extension to match the extension of the sample code you used.ibmcloud fn action create decode <filepath>/decode.js --web raw
Example output
ok: created action decode
-
Test the
decode
action by running the following cURL command.curl -k -H "content-type: application" -X POST -d "Decoded body" https://<apihost>/api/v1/web/<namespace_ID>/default/decode.json
Example output
{ "body": "Decoded body" }
Options requests
By default, an OPTIONS
request that is made to a web action results in CORS headers that are automatically added to the response headers. These headers allow all origins and the OPTIONS
, GET
, DELETE
,
POST
, PUT
, HEAD
, and PATCH
HTTP verbs.
See the following headers,
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, DELETE, POST, PUT, HEAD, PATCH
Access-Control-Allow-Headers: Authorization, Content-Type
Alternatively, OPTIONS
requests can be handled manually by a web action. To enable this option, add a web-custom-options
annotation with a value of true
to a web action. When this feature is enabled, CORS
headers are not automatically added to the request response. Instead, you must append your headers programmatically.
To create custom responses to OPTIONS
requests:
-
Save the following code to a file
custom-options.js
.function main(params) { if (params.__ow_method == "options") { return { headers: { 'Access-Control-Allow-Methods': 'OPTIONS, GET', 'Access-Control-Allow-Origin': 'example.com' }, statusCode: 200 } } }
-
Create the web action. Set the
--web-custom-options
totrue
.ibmcloud fn action create custom-option <filepath>/custom-options.js --web true -a web-custom-options true
-
Test the action by using the following cURL command.
curl https://<apihost>/api/v1/web/<namespace_ID>/default/custom-option.http -kvX OPTIONS
Example output
< HTTP/1.1 200 OK < Server: nginx/1.11.13 < Content-Length: 0 < Connection: keep-alive < Access-Control-Allow-Methods: OPTIONS, GET < Access-Control-Allow-Origin: example.com
Error handling
A Cloud Functions action fails in two different possible failure modes. The first is known as an application error, and is analogous to a caught exception: the action returns a JSON object that contains a top level error
property. The second is a developer error, which occurs when the action fails and does not produce a response (similar to an uncaught exception).
For web actions, the controller handles application errors as follows:
- Any specified path projection is ignored and the controller projects the
error
property instead. - The controller applies the content handling that is implied by the action extension to the value of the
error
property.
Developers must know how web actions might be used and then generate appropriate error responses. For example, a web action that is used with the .http
extension returns an HTTP response such as {error: { statusCode: 400 }
.
Failing to do so is a mismatch between the implied Content-Type
from the extension and the action Content-Type
in the error response. Special consideration must be given to web actions that are sequences so that components
that make up a sequence can generate adequate errors when necessary.
Disabling web actions
You can disable web actions from both the CLI and the console.
To disable a web action from the CLI,
ibmcloud fn action update <packageName>/<actionName> <filepath>/<filename> --web false
To disable a web action from the console,
- Go to the Action page.
- Click the web action that you want to disable.
- On the Endpoints tab, clear the selection for Enable as Web Action.
- Save your changes.
Web action limits
For more information about request and response limits for web actions, see System details and limits.