Create a Webassembly plugin with Extism and Rust

Photo by Jake Nackos on Unsplash

Create a Webassembly plugin with Extism and Rust

Before moving on to a more complicated article (creating an HTTP server in Go to serve WASM services), we will see how to develop an Extism plugin in Rust. You will see it is effortless, and it is an excellent opportunity to take your first steps in Rust.

Prerequisites

  • Extism 0.4.0: Install Extism

  • Rust:

    • Install Rust

        curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y
      
        echo 'export CARGO_HOME="~/.cargo"' >> ~/.bashrc
        echo 'export PATH=\$CARGO_HOME/bin:\$PATH' >> ~/.bashrc
      
        source ~/.cargo/env
        source ~/.bashrc
      

      I'm on Linux

    • Install Wasm Pack

        curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
      
    • Install the necessary wasm targets:

        rustup target add wasm32-wasi
        rustup target add wasm32-unknown-unknown
      
    • Install Wasm Bindgen:

        cargo install -f wasm-bindgen-cli
      
    • Install the components of the build toolchain according to your architecture:

        rustup component add rust-analysis --toolchain stable-aarch64-unknown-linux-gnu 
        rustup component add rust-src --toolchain stable-aarch64-unknown-linux-gnu 
        rustup component add rls --toolchain stable-aarch64-unknown-linux-gnu
      

      In my case, I use an ARM architecture

Generating the plugin project

To generate the Rust project, use the following command:

cargo new --lib hello-rust-plugin --name hello

This will create a folder hello-rust-plugin. In this folder, add this to the file Cargo.toml:

[lib]
crate_type = ["cdylib"]

So, the file Cargo.toml should have the following content:

[package]
name = "hello"
version = "0.1.0"
edition = "2021"

[lib]
crate_type = ["cdylib"]

[dependencies]

Then, add the dependencies:

cd hello-rust-plugin
cargo add extism-pdk
cargo add serde
cargo add serde_json

The [dependencies] section of Cargo.toml should look like this:

[dependencies]
extism-pdk = "0.3.3"
serde = "1.0.178"
serde_json = "1.0.104"

Modifying the source code

Then change the source code of src/lib.rs as follows:

#![no_main]

use extism_pdk::*;
use serde::Serialize;

#[derive(Serialize)]
struct Output {
    pub message: String,
}

#[plugin_fn]
pub fn hello(input: String) -> FnResult<Json<Output>> {

    let msg: String = "🦀 Hello ".to_string() + &input;

    let output = Output { message: msg };

    Ok(Json(output))
}

👋 You can notice that the Rust code of an Extism plugin is more straightforward than that of an Extism plugin in Go regarding the passing of parameters and the function's return value.

Compiling the plugin

To compile the plugin, type the commands below:

cargo clean
cargo build --release --target wasm32-wasi

The plugin hello.wasm has been generated in the following directory: ./target/wasm32-wasi/release

To test it, you need to use the following command:

extism call ./target/wasm32-wasi/release/hello.wasm \
  hello --input "Bob Morane"  \
  --wasi

And you will get:

{"message":"🦀 Hello Bob Morane"}

That's it; it's over. You have seen that starting the development of an Extism plugin with Rust is relatively easy. In the following article, which will be much longer, we will use this plugin to create a MicroService using a host application developed in Go.