Rhai Scripting
Avalon supports Rhai scripting for advanced request handling and URL rewriting. Rhai is a simple, safe scripting language embedded in Rust applications.
Basic Usage
[servers.routes.handle]
type = "script"
script = '''
// Access request information
let path = request.path;
let method = request.method;
let host = request.host;
let client_ip = request.client_ip;
// Return a response
response(200, "Hello, World!", #{})
'''
Request Object
| Property | Type | Description |
request.path | string | Request path |
request.method | string | HTTP method |
request.host | string | Request hostname |
request.client_ip | string | Client IP address |
request.query | string | Query string |
request.headers | map | Request headers (lowercase keys) |
Built-in Functions
Response Functions
| Function | Description | Example |
response(status, body, headers) | Return custom response | response(200, "OK", #{}) |
json_response(data) | Return JSON response | json_response(#{ key: "value" }) |
redirect(url) | 302 redirect | redirect("https://example.com") |
redirect_with_code(url, code) | Redirect with status code | redirect_with_code("/new", 301) |
String Functions
| Function | Description | Example |
url_encode(str) | URL encode | url_encode("hello world") |
url_decode(str) | URL decode | url_decode("hello%20world") |
base64_encode(str) | Base64 encode | base64_encode("hello") |
base64_decode(str) | Base64 decode | base64_decode("aGVsbG8=") |
regex_match(pattern, text) | Regex match | regex_match("^/api/", path) |
regex_replace(pattern, repl, text) | Regex replace | regex_replace("old", "new", text) |
JSON Functions
| Function | Description | Example |
json_parse(str) | Parse JSON | json_parse('{"a":1}') |
json_stringify(obj) | Stringify to JSON | json_stringify(#{ a: 1 }) |
Utility Functions
| Function | Description | Example |
query_param(name) | Get query parameter | query_param("page") |
hash_md5(str) | MD5 hash | hash_md5("password") |
hash_sha256(str) | SHA256 hash | hash_sha256("data") |
time_now() | Current Unix timestamp | time_now() |
Examples
API Gateway Routing
[servers.routes.handle]
type = "script"
script = '''
let path = request.path;
let api_key = request.headers["x-api-key"];
// Validate API key
if api_key != "secret-key-123" {
response(401, json_stringify(#{ error: "Invalid API key" }), #{
"Content-Type": "application/json"
})
} else if path.starts_with("/v1/users") {
// Forward to user service
#{ proxy: "user-service:8080" }
} else if path.starts_with("/v1/orders") {
// Forward to order service
#{ proxy: "order-service:8080" }
} else {
json_response(#{ error: "Not Found", path: path })
}
'''
A/B Testing
[servers.routes.handle]
type = "script"
script = '''
// Simple A/B test based on client IP
let ip_hash = hash_md5(request.client_ip);
let variant = if ip_hash.starts_with("0") || ip_hash.starts_with("1") {
"A"
} else {
"B"
};
response(200, "", #{
"X-AB-Variant": variant,
"Set-Cookie": "ab_variant=" + variant + "; Path=/; Max-Age=86400"
})
'''
Health Check Endpoint
[servers.routes.handle]
type = "script"
script = '''
if request.path == "/health" {
json_response(#{
status: "ok",
timestamp: time_now(),
version: "1.0.0"
})
} else {
response(404, "Not Found", #{})
}
'''
Request Logging
[servers.routes.handle]
type = "script"
script = '''
// Log request details
let log_entry = #{
path: request.path,
method: request.method,
client_ip: request.client_ip,
timestamp: time_now()
};
// Continue to proxy (this is a passthrough example)
#{ proxy: "backend:8080" }
'''
Rate Limit Response
[servers.routes.handle]
type = "script"
script = '''
// Check rate limit header
let remaining = request.headers["x-ratelimit-remaining"];
if remaining == "0" {
response(429, json_stringify(#{
error: "Too Many Requests",
retry_after: 60
}), #{
"Content-Type": "application/json",
"Retry-After": "60"
})
} else {
#{ proxy: "backend:8080" }
}
'''