Wasm Labs @ VMware OCTO

Wasm Workers Server 1.0: support for Python and Ruby

By Angel M Miguel
At 2023 / 02 15 mins reading

Wasm Workers Server is a WebAssembly framework to develop and run serverless applications. It aims to bring the benefits of WebAssembly to your apps without changing your development workflow. If you are new to Wasm Workers Server, here you have a quick 5 minutes introduction.

In v1.0.0, you can now write Workers-based applications in additional dynamic languages: Ruby and Python. Before, wws only identified .wasm modules and .js files as workers. Now, you can extend the supported languages by installing language runtimes locally.

By default, wws relies on the WebAssembly Languages Runtimes project, which has support for Python, Ruby, and PHP. From the wws CLI, you can list, install and use the available language runtimes and start creating new workers.

Can't wait to try it? Just update or install wws and try the new runtimes command:

curl -fsSL https://workers.wasmlabs.dev/install | bash && \
wws runtimes list

You will get the list of available language runtimes:

⚙️  Fetching data from the repository...
┌────────┬─────────┬───────────────────┬───────────┬─────────────┐
│ Name │ Version │ Tags │ Extension │ Binary │
├────────┼─────────┼───────────────────┼───────────┼─────────────┤
│ ruby │ 3.2.0 │ latest, 3, 3.2.0 │ rb │ ruby.wasm │
├────────┼─────────┼───────────────────┼───────────┼─────────────┤
│ python │ 3.11.1 │ latest, 3, 3.11.1 │ py │ python.wasm │
└────────┴─────────┴───────────────────┴───────────┴─────────────┘

The v1.0.0 version comes with more features. For example, we introduced dynamic routes and several bug fixes. We will dig into all of them in this article. If you prefer a video version, you can check all the new features on Youtube 👇

A thumbnail of the Multi-language support in Wasm Workers Server v1.0.0. This will link you to a youtube video of this article

Multi-language support

Reusing your existing knowledge, such as programming languages, is key to being productive. If you are used to developing applications with JavaScript, Ruby, or Python, we want you to be able to continue using them while leveraging new and exciting features. For this reason, we introduced a new command in wws to extend the number of programming languages to write workers.

By default, wws identifies .wasm modules and .js files as workers. With the new runtimes command, you can download different language runtimes to increase the number of supported languages. When you install a new language, wws downloads three main files:

  • The Wasm module that contains the language runtime.
  • A polyfill to provide the Request and Response entities.
  • A wrapper to connect your worker code with wws. It initializes the Request and formats the Response.

When you run any runtimes subcommand, it fetches the metadata from the Wasm Workers Server repository and downloads the binaries from the WebAssembly Languages Runtimes project. You can also configure your repository by following this guide.

Install a new language runtime

To install a new language runtime, check the available runtimes:

wws runtimes list

⚙️ Fetching data from the repository...
┌────────┬─────────┬───────────┬───────────┬─────────────┐
│ Name │ Version │ Tags │ Extension │ Binary │
├────────┼─────────┼───────────┼───────────┼─────────────┤
│ ruby │ 3.2.0 │ latest, 3 │ rb │ ruby.wasm │
├────────┼─────────┼───────────┼───────────┼─────────────┤
│ python │ 3.11.1 │ latest, 3 │ py │ python.wasm │
└────────┴─────────┴───────────┴───────────┴─────────────┘

Let's say you want to create a worker using Python. You can install the runtime using the name and alias:

wws runtimes install python latest

⚙️ Fetching data from the repository...
🚀 Installing the runtime...
✅ Done

Now, wws is ready to load .py files as workers! Note that wws stores the runtime in the current folder. It will detect the .py files in this folder and subfolders.

You may notice two new resources in your folder:

  • A .wws folder
  • A .wws.toml file

wws stores the runtimes required files in the .wws folder. The .wws.toml file contains the metadata of the installed runtimes. If you retrieve this project in a clean environment, you can install the required runtimes by running wws runtimes install. wws will read the metadata from the .wws.toml file and install the missing runtimes.

Your first Python worker

You are now ready to create your first Python worker! Let's begin with a simple "Hello World". For that, create a new index.py file. The file must include a worker function that receives a Request object and returns a Response one. You can use the code below:

def worker(req):
return Response("Hello from Python in Wasm")

After saving the file, run the wws command:

wws

⚙️ Loading routes from: .
🗺 Detected routes:
- http://127.0.0.1:8080/
=> ./index.py (name: default)
🚀 Start serving requests at http://127.0.0.1:8080

wws quickly identifies the index.py file as a worker. You can access http://localhost:8080 to see the result. As a next step, let's read the request details and modify some of the headers:

def worker(req):
# Body response
body = '''\
<!DOCTYPE html>
<body>
<h1>Hello from Wasm Workers Server</h1>
<p>Replying to {url}</p>
<p>Method: {method}</p>
<p>User Agent: {agent}</p>
<p>
This page was generated by a Python file inside WebAssembly
</p>
</body>
'''
.format(
url=req.url,
method=req.method,
agent=req.headers["user-agent"]
)

# Build a new response
res = Response(body)

# Add a new header
res.headers["x-generated-by"] = "wasm-workers-server"

return res

Restart wws and reload your page to see the changes.

A Safari screenshot showing the content from the Python worker

Your first Ruby worker

Wasm Workers Server allows you to mix programming languages in the same project. To create a new Ruby worker, first install the ruby runtime:

wws runtimes install ruby latest

⚙️ Fetching data from the repository...
🚀 Installing the runtime...
✅ Done

All workers follow the same Request / Response approach. To create your first Ruby worker, create a ruby.rb file and define a worker function:

def worker(req)
Response.new("Hello from Ruby in Wasm")
end

Now, run wws and check how both / and /ruby endpoints work together:

wws

⚙️ Loading routes from: .
🗺 Detected routes:
- http://127.0.0.1:8080/
=> ./index.py (name: default)
- http://127.0.0.1:8080/ruby
=> ./ruby.rb (name: default)
🚀 Start serving requests at http://127.0.0.1:8080

Finally, access http://localhost:8080/ruby to see the result.

Dynamic routes (parameters)

Apart from the addition of new language runtimes, we have additional major features to share with you! In v1.0.0, we introduced support for dynamic routes. In many cases, you want a worker to process multiple URLs. For example, your application may use identifiers to identify resources:

/room/iu812kjas
/room/jdki2312d
...

In v1.0.0, you can create workers that process multiple URLs by using the [PARAM_NAME].* pattern in the filename. For example, a worker called room/[room].js manages the previous URLs. The worker will receive a params object that includes the route parameter key and value ({ "room": "iu812kjas" }).

You can create dynamic routes using folders too. Imagine you have a players' subresource inside every room (like /room/ID/players). To create a worker to manage the players, add the identifier to the folder that contains the worker: room/[room]/players.js.

Your first dynamic route

This feature applies to all the supported languages, so let's try it with Python. First, create a new [id].py file in your current project. If you didn't install the Python runtime before, just run wws runtimes install python latest. In Python, you can retrieve the route parameters directly from the request instance:

def worker(req):
# Body response
body = '''\
<!DOCTYPE html>
<body>
<h1>Hello from Wasm Workers Server</h1>
<p>Replying to {url}</p>
<p>Parameter: {param}</p>
<p>
This page was generated by a Python file inside WebAssembly
</p>
</body>
'''
.format(
url=req.url,
param=req.params["id"]
)

return Response(body)

After restarting wws, access http://localhost:8080/python to see the result. The worker will receive python as the value for the id parameter.

A Safari screenshot showing the content from the Python worker. It includes the URL parameter

New documentation

The project documentation is available at workers.wasmlabs.dev. We introduced new sections about the project, supported languages, and new features. We are also introducing more video content for developers (like us) who sometimes prefer videos over text.

Please, feel free to provide feedback and suggestions to our documentation via Twitter or in the project issues.

Your workers, from any language, anywhere

The v1.0.0 release was a bit milestone. The team put a lot of effort into the language runtimes project. We want to provide a seamless developer experience for interpreted languages in WebAssembly. The goal is to make wws extensible, so you can install new language runtimes without releasing new wws versions.

In the upcoming weeks, we will publish more tutorials and guides about developing applications with wws. You can expect new articles, videos, examples, and documentation 🤓.

If you are developing some cool apps with wws, feel free to show them to us. We are eager to learn what you are building! You can find us on Twitter and in our GitHub repository ⭐️.

Do you want to stay up to date with WebAssembly and our projects?