home / skills / alibaba / higress / higress-wasm-go-plugin

higress-wasm-go-plugin skill

/.claude/skills/higress-wasm-go-plugin

This skill helps you develop Higress WASM plugins in Go, enabling secure HTTP processing, external calls, and gateway logic.

npx playbooks add skill alibaba/higress --skill higress-wasm-go-plugin

Review the files below or copy the command above to add this skill to your agents.

Files (5)
SKILL.md
7.3 KB
---
name: higress-wasm-go-plugin
description: Develop Higress WASM plugins using Go 1.24+. Use when creating, modifying, or debugging Higress gateway plugins for HTTP request/response processing, external service calls, Redis integration, or custom gateway logic.
---

# Higress WASM Go Plugin Development

Develop Higress gateway WASM plugins using Go language with the `wasm-go` SDK.

## Quick Start

### Project Setup

```bash
# Create project directory
mkdir my-plugin && cd my-plugin

# Initialize Go module
go mod init my-plugin

# Set proxy (China)
go env -w GOPROXY=https://proxy.golang.com.cn,direct

# Download dependencies
go get github.com/higress-group/[email protected]
go get github.com/higress-group/wasm-go@main
go get github.com/tidwall/gjson
```

### Minimal Plugin Template

```go
package main

import (
    "github.com/higress-group/wasm-go/pkg/wrapper"
    "github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
    "github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
    "github.com/tidwall/gjson"
)

func main() {}

func init() {
    wrapper.SetCtx(
        "my-plugin",
        wrapper.ParseConfig(parseConfig),
        wrapper.ProcessRequestHeaders(onHttpRequestHeaders),
    )
}

type MyConfig struct {
    Enabled bool
}

func parseConfig(json gjson.Result, config *MyConfig) error {
    config.Enabled = json.Get("enabled").Bool()
    return nil
}

func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig) types.Action {
    if config.Enabled {
        proxywasm.AddHttpRequestHeader("x-my-header", "hello")
    }
    return types.HeaderContinue
}
```

### Compile

```bash
go mod tidy
GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm ./
```

## Core Concepts

### Plugin Lifecycle

1. **init()** - Register plugin with `wrapper.SetCtx()`
2. **parseConfig** - Parse YAML config (auto-converted to JSON)
3. **HTTP processing phases** - Handle requests/responses

### HTTP Processing Phases

| Phase | Trigger | Handler |
|-------|---------|---------|
| Request Headers | Gateway receives client request headers | `ProcessRequestHeaders` |
| Request Body | Gateway receives client request body | `ProcessRequestBody` |
| Response Headers | Gateway receives backend response headers | `ProcessResponseHeaders` |
| Response Body | Gateway receives backend response body | `ProcessResponseBody` |
| Stream Done | HTTP stream completes | `ProcessStreamDone` |

### Action Return Values

| Action | Behavior |
|--------|----------|
| `types.HeaderContinue` | Continue to next filter |
| `types.HeaderStopIteration` | Stop header processing, wait for body |
| `types.HeaderStopAllIterationAndWatermark` | Stop all processing, buffer data, call `proxywasm.ResumeHttpRequest/Response()` to resume |

## API Reference

### HttpContext Methods

```go
// Request info (cached, safe to call in any phase)
ctx.Scheme()   // :scheme
ctx.Host()     // :authority
ctx.Path()     // :path
ctx.Method()   // :method

// Body handling
ctx.HasRequestBody()        // Check if request has body
ctx.HasResponseBody()       // Check if response has body
ctx.DontReadRequestBody()   // Skip reading request body
ctx.DontReadResponseBody()  // Skip reading response body
ctx.BufferRequestBody()     // Buffer instead of stream
ctx.BufferResponseBody()    // Buffer instead of stream

// Content detection
ctx.IsWebsocket()           // Check WebSocket upgrade
ctx.IsBinaryRequestBody()   // Check binary content
ctx.IsBinaryResponseBody()  // Check binary content

// Context storage
ctx.SetContext(key, value)
ctx.GetContext(key)
ctx.GetStringContext(key, defaultValue)
ctx.GetBoolContext(key, defaultValue)

// Custom logging
ctx.SetUserAttribute(key, value)
ctx.WriteUserAttributeToLog()
```

### Header/Body Operations (proxywasm)

```go
// Request headers
proxywasm.GetHttpRequestHeader(name)
proxywasm.AddHttpRequestHeader(name, value)
proxywasm.ReplaceHttpRequestHeader(name, value)
proxywasm.RemoveHttpRequestHeader(name)
proxywasm.GetHttpRequestHeaders()
proxywasm.ReplaceHttpRequestHeaders(headers)

// Response headers
proxywasm.GetHttpResponseHeader(name)
proxywasm.AddHttpResponseHeader(name, value)
proxywasm.ReplaceHttpResponseHeader(name, value)
proxywasm.RemoveHttpResponseHeader(name)
proxywasm.GetHttpResponseHeaders()
proxywasm.ReplaceHttpResponseHeaders(headers)

// Request body (only in body phase)
proxywasm.GetHttpRequestBody(start, size)
proxywasm.ReplaceHttpRequestBody(body)
proxywasm.AppendHttpRequestBody(data)
proxywasm.PrependHttpRequestBody(data)

// Response body (only in body phase)
proxywasm.GetHttpResponseBody(start, size)
proxywasm.ReplaceHttpResponseBody(body)
proxywasm.AppendHttpResponseBody(data)
proxywasm.PrependHttpResponseBody(data)

// Direct response
proxywasm.SendHttpResponse(statusCode, headers, body, grpcStatus)

// Flow control
proxywasm.ResumeHttpRequest()   // Resume paused request
proxywasm.ResumeHttpResponse()  // Resume paused response
```

## Common Patterns

### External HTTP Call

See [references/http-client.md](references/http-client.md) for complete HTTP client patterns.

```go
func parseConfig(json gjson.Result, config *MyConfig) error {
    serviceName := json.Get("serviceName").String()
    servicePort := json.Get("servicePort").Int()
    config.client = wrapper.NewClusterClient(wrapper.FQDNCluster{
        FQDN: serviceName,
        Port: servicePort,
    })
    return nil
}

func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig) types.Action {
    err := config.client.Get("/api/check", nil, func(statusCode int, headers http.Header, body []byte) {
        if statusCode != 200 {
            proxywasm.SendHttpResponse(403, nil, []byte("Forbidden"), -1)
            return
        }
        proxywasm.ResumeHttpRequest()
    }, 3000) // timeout ms
    
    if err != nil {
        return types.HeaderContinue // fallback on error
    }
    return types.HeaderStopAllIterationAndWatermark
}
```

### Redis Integration

See [references/redis-client.md](references/redis-client.md) for complete Redis patterns.

```go
func parseConfig(json gjson.Result, config *MyConfig) error {
    config.redis = wrapper.NewRedisClusterClient(wrapper.FQDNCluster{
        FQDN: json.Get("redisService").String(),
        Port: json.Get("redisPort").Int(),
    })
    return config.redis.Init(
        json.Get("username").String(),
        json.Get("password").String(),
        json.Get("timeout").Int(),
    )
}
```

### Multi-level Config

插件配置支持在控制台不同级别设置:全局、域名级、路由级。控制面会自动处理配置的优先级和匹配逻辑,插件代码中通过 `parseConfig` 解析到的就是当前请求匹配到的配置。

## Local Testing

See [references/local-testing.md](references/local-testing.md) for Docker Compose setup.

## Advanced Topics

See [references/advanced-patterns.md](references/advanced-patterns.md) for:
- Streaming body processing
- Route call pattern
- Tick functions (periodic tasks)
- Leader election
- Memory management
- Custom logging

## Best Practices

1. **Never call Resume after SendHttpResponse** - Response auto-resumes
2. **Check HasRequestBody() before returning HeaderStopIteration** - Avoids blocking
3. **Use cached ctx methods** - `ctx.Path()` works in any phase, `GetHttpRequestHeader(":path")` only in header phase
4. **Handle external call failures gracefully** - Return `HeaderContinue` on error to avoid blocking
5. **Set appropriate timeouts** - Default HTTP call timeout is 500ms

Overview

This skill helps you develop Higress WASM gateway plugins using Go 1.24+ and the higress wasm-go SDK. It targets HTTP request/response processing, external service calls, Redis integration, and custom gateway logic for AI-native API gateways. The content provides templates, lifecycle details, API reference, and common patterns to accelerate plugin development and debugging.

How this skill works

The skill shows how to register a plugin, parse per-route or global YAML config (auto-converted to JSON), and implement handlers for HTTP lifecycle phases (request headers/body, response headers/body, stream done). It documents the proxywasm APIs for header/body manipulation, direct responses, flow control (pause/resume), and context storage. Examples include making asynchronous cluster HTTP calls and Redis access with built-in flow control and timeout patterns.

When to use it

  • Creating a new Higress WASM plugin in Go to inspect or modify HTTP traffic
  • Adding external service validation or enrichment (HTTP calls, Redis) inside the gateway
  • Implementing request/response body transformations or streaming processing
  • Debugging plugin lifecycle, flow control, or header/body access issues
  • Building multi-level configurable plugins (global/domain/route) that rely on parsed config

Best practices

  • Register plugin and handlers in init() using wrapper.SetCtx to ensure lifecycle hooks are set
  • Parse per-request config with parseConfig; control plane supplies the effective config
  • Never call Resume after SendHttpResponse — responses auto-resume after send
  • Check HasRequestBody()/HasResponseBody() before using HeaderStopIteration to avoid deadlocks
  • Return HeaderContinue on external call errors to fail open and avoid blocking requests
  • Set explicit timeouts for cluster/HTTP calls (default is short) and handle timeouts gracefully

Example use cases

  • Append a custom header on inbound requests when a route-level flag is enabled
  • Call an authentication service during request headers phase; block or allow based on result
  • Fetch rate limit state from Redis and return 429 when quota is exceeded
  • Stream and transform response bodies for content filtering or watermarking
  • Implement periodic health or leader-election tasks using tick functions for background work

FAQ

How do I compile a Go WASM plugin for Higress?

Use GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm after adding the higress wasm-go SDK and proxy-wasm-go-sdk dependencies.

Can I buffer request or response bodies?

Yes. Use ctx.BufferRequestBody() or ctx.BufferResponseBody() to buffer instead of streaming, and only access body data in the body phase.