--- title: WASM Custom Rules description: Use WebAssembly modules as custom body matchers in MockServer for complex matching logic that runs in a sandboxed WASM interpreter. layout: page pageOrder: 32 section: 'General' subsection: true sitemap: priority: 0.7 changefreq: 'monthly' ---

## WASM Custom Body Matchers

MockServer supports WebAssembly (WASM) modules as custom body matchers. This lets you write complex matching logic in any language that compiles to WASM (Rust, C, Go, AssemblyScript, etc.) and upload the compiled module to MockServer at runtime.

The WASM module runs inside a pure-Java interpreter (chicory), so no native libraries or JNI are required. The module is sandboxed and cannot access the host filesystem, network, or JVM.

### Enabling WASM support

WASM body matching is disabled by default. Enable it with:

    # environment variable
    MOCKSERVER_WASM_ENABLED=true

    # Java system property
    -Dmockserver.wasmEnabled=true

    # configuration property file
    mockserver.wasmEnabled=true

### Writing a WASM matcher module

Your WASM module must export a function called match with the following signature:

    ;; WAT (WebAssembly Text Format)
    (module
      (memory (export "memory") 1)
      (func $match (export "match") (param $ptr i32) (param $len i32) (result i32)
        ;; Read $len bytes from linear memory starting at $ptr
        ;; Return 1 for match, 0 for no match
        i32.const 1  ;; always matches (example)
      )
    )

Before calling match, MockServer writes the HTTP request body (UTF-8 encoded) into the module's linear memory at offset 0. The $ptr parameter is 0 and $len is the byte length of the body.

#### Rust example

    #[no_mangle]
    pub extern "C" fn match_fn(ptr: *const u8, len: usize) -> i32 {
        let body = unsafe { std::slice::from_raw_parts(ptr, len) };
        let body_str = std::str::from_utf8(body).unwrap_or("");
        if body_str.contains("expected_value") { 1 } else { 0 }
    }

Note: When compiling Rust to WASM, export the function as match (you may need #[export_name = "match"] since match is a Rust keyword).

### Uploading a WASM module

Upload a compiled WASM module using the REST API:

    # Upload a WASM module named "myMatcher"
    curl -X PUT "http://localhost:1080/mockserver/wasm/modules?name=myMatcher" \
      --data-binary @my_matcher.wasm

### Using a WASM body matcher in an expectation

    {
      "httpRequest": {
        "method": "POST",
        "path": "/api/data",
        "body": {
          "type": "WASM",
          "moduleName": "myMatcher"
        }
      },
      "httpResponse": {
        "statusCode": 200,
        "body": "matched by WASM rule"
      }
    }

### Managing WASM modules

#### List loaded modules

    curl http://localhost:1080/mockserver/wasm/modules
    # Returns: ["myMatcher", "anotherModule"]

#### Remove a module

    curl -X DELETE "http://localhost:1080/mockserver/wasm/modules?name=myMatcher"

All WASM modules are also cleared when calling PUT /mockserver/reset.

### Configuration properties

Property | Environment Variable | Default | Description
--- | --- | --- | ---
mockserver.wasmEnabled | MOCKSERVER_WASM_ENABLED | false | Enable WASM body matching. Must be set to true to use WASM modules.
mockserver.wasmMaxMemoryPages | MOCKSERVER_WASM_MAX_MEMORY_PAGES | 256 | Maximum number of WASM linear memory pages (each page is 64 KiB). Default 256 = 16 MiB.

### Error handling

WASM matching uses a fail-closed design. If any error occurs during matching (module not found, invalid WASM binary, runtime trap, missing match export), the matcher returns no match rather than throwing an exception. This prevents a broken WASM module from disrupting other expectations.

### Security

- WASM modules run inside the chicory interpreter sandbox -- they cannot access the host filesystem, network, or JVM internals
- Memory is capped by wasmMaxMemoryPages to prevent resource exhaustion
- The feature is opt-in (disabled by default)
- All WASM control-plane endpoints respect MockServer's authentication settings (mTLS/JWT)