Skip to main content

Zig

Zig workers are tested with Zig version 0.11.0. Then, they are loaded by Wasm Workers Server and start processing requests.

Your first Zig worker​

The recommended way to implement workers is by using the worker.ServeFunc function.

In this example, the worker will get a request and print all the related information.

  1. Create a new Zig project:

    zig init-exe
  2. Add Wasm Workers Server Zig dependency

    At this point in time Zigs Package manager is not yet available. We will therefore clone the repository to make the library locally available.

    mkdir lib
    wget -O ./lib/worker.zig https://raw.githubusercontent.com/vmware-labs/wasm-workers-server/main/kits/zig/worker/worker.zig
  3. Edit the src/main.zig to match the following contents:

    worker.zig
    const std = @import("std");
    const worker = @import("worker");

    fn requestFn(resp: *worker.Response, r: *worker.Request) void {
    _ = r;

    _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
    _ = &resp.writeAll("hello from zig");
    }

    pub fn main() !void {
    worker.ServeFunc(requestFn);
    }
  4. Additionally, you can now go further add all the information from the received worker.Request:

    worker.zig
    const std = @import("std");
    const worker = @import("worker");

    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const allocator = arena.allocator();

    fn requestFn(resp: *worker.Response, r: *worker.Request) void {
    std.debug.print("Hello from function\n", .{ });

    // // TODO: prepare to read request body and send it back
    std.debug.print("+++ doing payload \n", .{ });

    var payload: []const u8 = "";
    var reqBody = r.data;

    if (reqBody.len == 0) {
    payload = "-";
    } else {
    payload = reqBody;
    }

    const s =
    \\<!DOCTYPE html>
    \\<head>
    \\<title>Wasm Workers Server</title>
    \\<meta name="viewport" content="width=device-width,initial-scale=1">
    \\<meta charset="UTF-8">
    \\<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">
    \\<style>
    \\body {{ max-width: 1000px; }}
    \\main {{ margin: 5rem 0; }}
    \\h1, p {{ text-align: center; }}
    \\h1 {{ margin-bottom: 2rem; }}
    \\pre {{ font-size: .9rem; }}
    \\pre > code {{ padding: 2rem; }}
    \\p {{ margin-top: 2rem; }}
    \\</style>
    \\</head>
    \\<body>
    \\<main>
    \\<h1>Hello from Wasm Workers Server 👋</h1>
    \\<pre><code>Replying to {s}
    \\Method: {s}
    \\User Agent: {s}
    \\Payload: {s}</code></pre>
    \\<p>
    \\This page was generated by a Zig⚡️ file running in WebAssembly.
    \\</p>
    \\</main>
    \\</body>
    ;

    var body = std.fmt.allocPrint(allocator, s, .{ r.url.path, r.method, "-", payload }) catch undefined;

    _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
    _ = &resp.writeAll(body);
    }

    pub fn main() !void {
    worker.ServeFunc(requestFn);
    }
  5. Compile the project

    zig build-exe src/main.zig \
    --name worker \
    -mexec-model=reactor \
    -target wasm32-wasi \
    --mod worker::lib/worker.zig \
    --deps worker

    You can also use a build script to build the project with a simple zig build, please find some inspiration in our zig examples.

  6. Run your worker with wws. If you didn't download the wws server yet, check our Getting Started guide.

    wws .

    ⚙️ Loading routes from: .
    🗺 Detected routes:
    - http://127.0.0.1:8080/worker
    => worker.wasm (name: default)
    🚀 Start serving requests at http://127.0.0.1:8080
  7. Finally, open http://127.0.0.1:8080/worker in your browser.

Add a Key / Value store​

Wasm Workers allows you to add a Key / Value store to your workers. Read more information about this feature in the Key / Value store section.

To add a KV store to your worker, follow these steps:

  1. Create a new Zig project:

    zig init-exe
  2. Add Wasm Workers Server Zig dependency

    At this point in time Zigs Package manager is not yet available. We will therefore clone the repository to make the library locally available.

    mkdir lib
    wget -O ./lib/worker.zig https://raw.githubusercontent.com/vmware-labs/wasm-workers-server/main/kits/zig/worker/worker.zig ./lib
  3. Edit src/main.zig file with the following contents:

    main.zig
    const std = @import("std");
    const worker = @import("worker");

    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const allocator = arena.allocator();

    fn requestFn(resp: *worker.Response, r: *worker.Request) void {
    var cache = r.context.cache;
    var counter: i32 = 0;

    var v = cache.getOrPut("counter") catch undefined;

    if (!v.found_existing) {
    v.value_ptr.* = "0";
    } else {
    var counterValue = v.value_ptr.*;
    var num = std.fmt.parseInt(i32, counterValue, 10) catch undefined;
    counter = num + 1;
    var num_s = std.fmt.allocPrint(allocator, "{d}", .{ counter }) catch undefined;
    _ = cache.put("counter", num_s) catch undefined;
    }

    const s =
    \\<!DOCTYPE html>
    \\<head>
    \\<title>
    \\Wasm Workers Server - KV example</title>
    \\<meta name="viewport" content="width=device-width,initial-scale=1">
    \\<meta charset="UTF-8">
    \\</head>
    \\<body>
    \\<h1>Key / Value store in Zig</h1>
    \\<p>Counter: {d}</p>
    \\<p>This page was generated by a Zig⚡️ file running in WebAssembly.</p>
    \\</body>
    ;

    var body = std.fmt.allocPrint(allocator, s, .{ counter }) catch undefined; // add useragent

    _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
    _ = &resp.writeAll(body);
    }

    pub fn main() !void {
    worker.ServeFunc(requestFn);
    }
  4. Compile the project

    zig build-exe src/main.zig \
    --name worker-kv \
    -mexec-model=reactor \
    -target wasm32-wasi \
    --mod worker::lib/worker.zig \
    --deps worker

    You can also use a build script to build the project with a simple zig build, please find some inspiration in our zig examples.

  5. Create a worker-kv.toml file with the following content. Note the name of the TOML file must match the name of the worker. In this case we have worker-kv.wasm and worker-kv.toml in the same folder:

    worker-kv.toml
    name = "workerkv"
    version = "1"

    [data]
    [data.kv]
    namespace = "workerkv"
  6. Run your worker with wws. If you didn't download the wws server yet, check our Getting Started guide.

    wws .

    ⚙️ Loading routes from: .
    🗺 Detected routes:
    - http://127.0.0.1:8080/worker-kv
    => worker-kv.wasm (name: default)
    🚀 Start serving requests at http://127.0.0.1:8080
  7. Finally, open http://127.0.0.1:8080/worker-kv in your browser.

Dynamic routes​

You can define dynamic routes by adding route parameters to your worker files (like [id].wasm). To read them in Zig, follow these steps:

  1. Use the worker.ParamsKey context value to read in the passed in parameters:

    main.zig
    const std = @import("std");
    const worker = @import("worker");

    fn requestFn(resp: *worker.Response, r: *worker.Request) void {
    var params = r.context.params;

    ...
    }
  2. Then, you can read the values as follows:

    main.zig
    const std = @import("std");
    const worker = @import("worker");

    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const allocator = arena.allocator();

    fn requestFn(resp: *worker.Response, r: *worker.Request) void {
    var params = r.context.params;

    var id: []const u8 = "the value is not available";

    var v = params.get("id");

    if (v) |val| {
    id = val;
    }

    const s =
    \\Hey! The parameter is: {s}
    ;

    var body = std.fmt.allocPrint(allocator, s, .{ id }) catch undefined; // add useragent

    _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
    _ = &resp.writeAll(body);
    }

    pub fn main() !void {
    worker.ServeFunc(requestFn);
    }
  3. Compile the project

    zig build-exe src/main.zig \
    --name "[id]" \
    -mexec-model=reactor \
    -target wasm32-wasi \
    --mod worker::lib/worker.zig \
    --deps worker

    You can also use a build script to build the project with a simple zig build, please find some inspiration in our zig examples.

  4. Run your worker with wws. If you didn't download the wws server yet, check our Getting Started guide.

    wws .

    ⚙️ Loading routes from: .
    🗺 Detected routes:
    - http://127.0.0.1:8080/[id]
    => worker-kv.wasm (name: default)
    🚀 Start serving requests at http://127.0.0.1:8080
  5. Finally, open http://127.0.0.1:8080/hello in your browser.

Other examples​

Find other examples in the /examples directory of wasm-workers-server repository.

Contributors​

The Zig kit was originally authored by Christoph Voigt (@voigt).

Feature compatibility​

Workers' features that are available in Zig:

K/V StoreEnvironment VariablesDynamic RoutesFoldersHTTP Requests
✅✅✅✅❌