Creating and invoking Rust actions

The process of creating Rust actions is similar to that of other actions. The following sections guide you through creating and invoking a single Rust action, and demonstrate how to bundle multiple Rust files and third party dependencies.

An example action Rust action is simply a top-level function. For example, create a file called hello.rs with the following source code:

extern crate serde_json;

use serde_derive::{Deserialize, Serialize};
use serde_json::{Error, Value};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Input {
    #[serde(default = "stranger")]
    name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Output {
    greeting: String,
}

fn stranger() -> String {
    "stranger".to_string()
}

pub fn main(args: Value) -> Result<Value, Error> {
    let input: Input = serde_json::from_value(args)?;
    let output = Output {
        greeting: format!("Hello, {}", input.name),
    };
    serde_json::to_value(output)
}

Rust actions are mainly composed by a main function that accepts a JSON serdes Value as input and returns a Result including a JSON serde Value.

An action supports not only a JSON object but also a JSON array as a return value.

It would be a simple example that uses an array as a return value:

extern crate serde_json;
use serde_derive::{Deserialize, Serialize};
use serde_json::{Error, Value};
pub fn main(args: Value) -> Result<Value, Error> {
    let output = ["a", "b"];
    serde_json::to_value(output)
}

You can also create a sequence action with actions accepting an array param and returning an array result.

You can easily figure out the parameters with the following example:

extern crate serde_json;
use serde_derive::{Deserialize, Serialize};
use serde_json::{Error, Value};
pub fn main(args: Value) -> Result<Value, Error> {
    let inputParam = args.as_array();
    let defaultOutput = ["c", "d"];
    match inputParam {
        None => serde_json::to_value(defaultOutput),
        Some(x) => serde_json::to_value(x),
    }
}

The entry method for the action is main by default but may be specified explicitly when creating the action with the wsk CLI using --main, as with any other action type.

You can create an OpenWhisk action called helloRust from this function as follows:

wsk action create helloRust --kind rust:1.34 hello.rs

The CLI automatically infers the type of the action from the source file extension. For .rs source files, the action runs using a Rust v1.34 runtime.

Action invocation is the same for Rust actions as it is for any other actions:

wsk action invoke --result helloRust --param name World
  {
      "greeting": "Hello World!"
  }

Find out more about parameters in the Working with parameters section.

Packaging Rust actions in zip files

If your action needs external dependencies, you need to provide a zip file including your source and your cargo file with all your dependencies. The filename of the source file containing the entry point (e.g., main) must be lib.rs. The folder structure should be as follows:

|- Cargo.toml
|- src
    |- lib.rs

Here is an example of a Cargo.toml file

[package]
name = "actions"
version = "0.1.0"
authors = ["John Doe <john@doe.com>"]
edition = "2018"

[dependencies]
serde_json = "1.0"
serde = "1.0"
serde_derive = "1.0"

To zip your folder:

zip -r helloRust.zip Cargo.toml src

and then create the action:

wsk action create helloRust --kind rust:1.34 helloRust.zip