The traditional support for the dictionary still works:
import Foundation
func main(args: Any) -> Any {
let dict = args as! [String:Any]
if let name = dict["name"] as? String {
return [ "greeting" : "Hello \(name)!" ]
} else {
return [ "greeting" : "Hello stranger!" ]
}
}
For the return result, not only support dictionary
, but also support array
So a very simple hello array
function would be:
func main(args: Any) -> Any {
var arr = ["a", "b"]
return arr
}
And support array result for sequence action as well, the first action's array result can be used as next action's input parameter.
So the function can be:
func main(args: Any) -> Any {
return args
}
When invoking the above action, we can pass an array object as the input parameter.
Some examples of using Codable In and Out
Create file helloCodableAsync.swift
import Foundation
// Domain model/entity
struct Employee: Codable {
let id: Int?
let name: String?
}
// codable main function
func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
// For simplicity, just passing same Employee instance forward
respondWith(input, nil)
}
wsk action update helloCodableAsync helloCodableAsync.swift swift:5.1
ok: updated action helloCodableAsync
wsk action invoke helloCodableAsync -r -p id 73 -p name Andrea
{
"id": 73,
"name": "Andrea"
}
Create file helloCodableAsync.swift
import Foundation
struct Employee: Codable {
let id: Int?
let name: String?
}
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
// Return real error
do {
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
} catch {
respondWith(nil, error)
}
}
wsk action update helloCodableError helloCodableError.swift swift:5.1
ok: updated action helloCodableError
wsk action invoke helloCodableError -b -p id 51 -p name Carlos
{
"name": "helloCodableError",
"response": {
"result": {
"error": "insufficientFunds(5)"
},
"status": "application error",
"success": false
}
}
When you create an OpenWhisk Swift action with a Swift source file, it has to be compiled into a binary before the action is run. Once done, subsequent calls to the action are much faster until the container holding your action is purged. This delay is known as the cold-start delay.
To avoid the cold-start delay, you can compile your Swift file into a binary and then upload to OpenWhisk in a zip file. As you need the OpenWhisk scaffolding, the easiest way to create the binary is to build it within the same environment as it will be run in.
Use the docker container and pass the single source file as stdin.
Pass the name of the method to the flag -compile
docker run -i openwhisk/action-swift-v5.1 -compile main <main.swift >../action.zip
Use the docker container and pass a zip archive containing a Package.swift
and source files a main source file in the location Sources/main.swift
.
zip - -r * | docker run -i openwhisk/action-swift-v5.1 -compile main >../action.zip
For more build examples see here
In addition to previous ways of defining an action is now possible to use throwing async/await inside the action.
func action(args: Any) async throws -> Any {
//async code sleep for 1 sec
try await Task.sleep(nanoseconds: 1_000_000_000)
let newArgs = args as! [String:Any]
if let name = newArgs["name"] as? String {
return [ "greeting" : "Hello \(name)!" ]
} else {
return [ "greeting" : "Hello stranger!" ]
}
}
struct Input: Codable {
let name: String?
}
struct Output: Codable {
let count: Int
}
func action(input: Input) async throws -> Output? {
try await Task.sleep(nanoseconds: 1_000_000_000)
if let name = input.name {
return Output(count: name.count)
} else {
return Output(count: 0)
}
}
struct Input: Codable {
let name: String?
}
struct Output: Codable {
let count: Int
}
func action() async throws -> Output? {
try await Task.sleep(nanoseconds: 1_000_000_000)
return Output(count: 0)
}
In the following example, the main action decodes the URL from AnInput
, downloads the content from the URL, decodes the JSON and returns the response
in AnOutput
.
In case of failure, the runtime will return an error.
import AsyncHTTPClient
import Foundation
import _Concurrency
import NIOCore
import NIOFoundationCompat
enum RequestError: Error {
case requestError
}
struct AnInput: Codable {
let url: String?
}
struct AnOutput: Codable {
let args: [String: String]
let headers: [String: String]
let origin: String
let url: String
}
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
let decoder = JSONDecoder()
func main(param: AnInput) async throws -> AnOutput {
let echoURL = param.url ?? "https://httpbin.org/get"
let request = HTTPClientRequest(url: echoURL)
let response = try await httpClient.execute(request, timeout: .seconds(3))
if response.status == .ok {
let bytes = try await response.body.collect(upTo: 1024 * 1024) // 1 MB Buffer
let data = Data(buffer: bytes)
return try decoder.decode(AnOutput.self, from: data)
} else {
throw RequestError.requestError
}
}
The full swift package is here.
Note that the package of this action contains a dependency from AsynHTTPClient
, in such case, it's preferred to build the action.
zip - -r * | docker run -i openwhisk/action-swift-v5.7 -compile main >../action.zip