Wasm
Use Wasm middleware in your HTTP pipeline
WebAssembly is a way to safely run code compiled in other languages. Runtimes execute WebAssembly Modules (Wasm), which are most often binaries with a .wasm
extension.
The Wasm HTTP middleware allows you to manipulate an incoming request or serve a response with custom logic compiled to a Wasm binary. In other words, you can extend Dapr using external files that are not pre-compiled into the daprd
binary. Dapr embeds wazero to accomplish this without CGO.
Wasm binaries are loaded from a URL. For example, the URL file://rewrite.wasm
loads rewrite.wasm
from the current directory of the process. On Kubernetes, see How to: Mount Pod volumes to the Dapr sidecar to configure a filesystem mount that can contain Wasm modules. It is also possible to fetch the Wasm binary from a remote URL. In this case, the URL must point exactly to one Wasm binary. For example:
http://example.com/rewrite.wasm
, orhttps://example.com/rewrite.wasm
.
Component format
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: wasm
spec:
type: middleware.http.wasm
version: v1
metadata:
- name: url
value: "file://router.wasm"
- guestConfig
value: {"environment":"production"}
Spec metadata fields
Minimally, a user must specify a Wasm binary implements the http-handler. How to compile this is described later.
Field | Details | Required | Example |
---|---|---|---|
url | The URL of the resource including the Wasm binary to instantiate. The supported schemes include file:// , http:// , and https:// . The path of a file:// URL is relative to the Dapr process unless it begins with / . | true | file://hello.wasm , https://example.com/hello.wasm |
guestConfig | An optional configuration passed to Wasm guests. Users can pass an arbitrary string to be parsed by the guest code. | false | environment=production ,{“environment”:”production”} |
Dapr configuration
To be applied, the middleware must be referenced in configuration. See middleware pipelines.
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: appconfig
spec:
httpPipeline:
handlers:
- name: wasm
type: middleware.http.wasm
Note: WebAssembly middleware uses more resources than native middleware. This result in a resource constraint faster than the same logic in native code. Production usage should Control max concurrency.
Generating Wasm
This component lets you manipulate an incoming request or serve a response with custom logic compiled using the http-handler Application Binary Interface (ABI). The handle_request
function receives an incoming request and can manipulate it or serve a response as necessary.
To compile your Wasm, you must compile source using a http-handler compliant guest SDK such as TinyGo.
Here’s an example in TinyGo:
package main
import (
"strings"
"github.com/http-wasm/http-wasm-guest-tinygo/handler"
"github.com/http-wasm/http-wasm-guest-tinygo/handler/api"
)
func main() {
handler.HandleRequestFn = handleRequest
}
// handleRequest implements a simple HTTP router.
func handleRequest(req api.Request, resp api.Response) (next bool, reqCtx uint32) {
// If the URI starts with /host, trim it and dispatch to the next handler.
if uri := req.GetURI(); strings.HasPrefix(uri, "/host") {
req.SetURI(uri[5:])
next = true // proceed to the next handler on the host.
return
}
// Serve a static response
resp.Headers().Set("Content-Type", "text/plain")
resp.Body().WriteString("hello")
return // skip the next handler, as we wrote a response.
}
If using TinyGo, compile as shown below and set the spec metadata field named “url” to the location of the output (for example, file://router.wasm
):
tinygo build -o router.wasm -scheduler=none --no-debug -target=wasi router.go`
Wasm guestConfig
example
Here is an example of how to use guestConfig
to pass configurations to Wasm. In Wasm code, you can use the function handler.Host.GetConfig
defined in guest SDK to get the configuration. In the following example, the Wasm middleware parses the executed environment
from JSON config defined in the component.
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: wasm
spec:
type: middleware.http.wasm
version: v1
metadata:
- name: url
value: "file://router.wasm"
- guestConfig
value: {"environment":"production"}
Here’s an example in TinyGo:
package main
import (
"encoding/json"
"github.com/http-wasm/http-wasm-guest-tinygo/handler"
"github.com/http-wasm/http-wasm-guest-tinygo/handler/api"
)
type Config struct {
Environment string `json:"environment"`
}
func main() {
// get config bytes, which is the value of guestConfig defined in the component.
configBytes := handler.Host.GetConfig()
config := Config{}
json.Unmarshal(configBytes, &config)
handler.Host.Log(api.LogLevelInfo, "Config environment: "+config.Environment)
}
Related links
Last modified March 21, 2024: Merge pull request #4082 from newbe36524/v1.13 (f4b0938)