Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Calling an OpenWhisk Action in Swift

DZone's Guide to

Calling an OpenWhisk Action in Swift

OpenWhisk's Swift environment has methods built in to call actions. This guide will walk you through creating and invoking an action with Swift.

· Cloud Zone ·
Free Resource

Discover a centralized approach to monitor your virtual infrastructure, on-premise IT environment, and cloud infrastructure – all on a single platform.

As OpenWhisk is a Functions-as-a-Service system, it makes sense to create actions that do one thing and call other actions when they want other work done. As an example, in DrinksChooser, the choose action calls the incrementDrinkCount action, which increments the count of the recommended drink in Redis. This way,  choose doesn't have to know anything about Redis as that's not its job.

In OpenWhisk's Swift environment, there's the Whisk.invoke() method to do this. This is how we do it.

let env = ProcessInfo.processInfo.environment
let namespace : String = env["__OW_NAMESPACE"] ?? ""
let incrementAction = "/" + namespace + "/DC/incrementDrinkCount"
 
let invokeResult = Whisk.invoke(actionNamed: incrementAction,
        withParameters: ["name": drink])
let result = JSON(invokeResult)


The Action's Name

To invoke an action, we need it's fully qualified name. This is your OpenWhisk namespace concatenated with the action's name, including its package name if it has one.

Let's start with the namespace:

let env = ProcessInfo.processInfo.environment
let namespace : String = env["__OW_NAMESPACE"] ?? ""


Conveniently, the namespace is held in an environment variable called __OW_NAMESPACE. In Swift, we can retrieve environment variables from the ProcessInfo.processInfo.environment which will return an Optional String. As we're lazy, we convert the Optional to a concrete String using ?? "". In a proper application, we'd implement Swift's error handling and do it properly.

Note that the namespace doesn't start with a leading /, but our fully qualified action name does, so we create our action name like this:

let name = "/" + namespace + "/DC/incrementDrinkCount"


The action's name is incrementDrinkCount and it's in the DC package, so we add those in to create our action name.

Invoke the Action

Invoking the action is easy enough:

let p = ["name": "A nice hot cup of tea!"]
let result = Whisk.invoke(actionNamed: name, withParameters: p)


We call Whisk.invoke() with our action name and a dictionary of parameters if we have any. In our case, we pass in the name of the drink whose count we want to increment.

The action is executed and the result is returned as a dictionary of type [String:Any].

Data Returned From Whisk.invoke()

You get a dictionary back from Whisk.invoke() with lots of interesting information:

[
    "activationId": "f91ac41933274f8eb191082a834f70a4",
    "annotations": [
        [
            "key": "limits",
            "value": [
                "logs": 10,
                "memory": 256,
                "timeout": 60000
            ]
        ],
        [
            "key": "path",
            "value": "19FT_dev/DC/incrementDrinkCount"
        ]
    ],
    "duration": 40,
    "end": 1488230688926,
    "logs": [],
    "name": "incrementDrinkCount",
    "namespace": "19FT_dev",
    "publish": false,
    "response": [
        "result": [
            "drink": "A nice hot cup of tea!",
            "new_count": "24"
        ],
        "status": "success",
        "success": true
    ],
    "start": 1488230663040,
    "version": "0.0.3"
]


The interesting information is in the response dictionary, and the first thing to check is the success key, which is a boolean and thus is either true or false:

let response = result["response"] as! Dictionary<String, Any>
if response["success"] as! Bool == false {
    return ["error": "incrementDrinkCount failed"]
}


As you can see, we have to downcast a lot.

As the type of the dictionary is [String:Any], we have to downcast all the time!

To make this easier, we can use the SwiftyJSON library, which handles the casting for us:

let jsonResult = JSON(result)
if jsonResult["response"]["success"].boolValue == false {
    return ["error": "incrementDrinkCount failed"]
}


This becomes even more useful as we delve deeper into a nested dictionary!

Learn how to auto-discover your containers and monitor their performance, capture Docker host and container metrics to allocate host resources, and provision containers.

Topics:
openwhisk ,cloud ,swift ,functions ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}