Help us shape the future of Go! Take the 2026 Go Developer Survey

lua

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

README

Lua Services Package

This package provides Lua services for use with the LuaDataSource. These services expose Go functionality to Lua scripts in a safe and controlled manner.

Available Services

HTTP Service

The HTTP service provides HTTP client functionality to Lua scripts.

Functions
  • http.get(url, [headers]) - Make a GET request

    • Returns: {status=int, body=string, headers=table} or (nil, error)
  • http.post(url, body, [headers]) - Make a POST request

    • Returns: {status=int, body=string, headers=table} or (nil, error)
  • http.request(method, url, [body], [headers]) - Make a generic HTTP request

    • Returns: {status=int, body=string, headers=table} or (nil, error)

URLs may be absolute (https://host/path) or relative (/v1/compliance). Relative URLs resolve against the HTTP client's optional base_url (WithBaseURL). base_url must be origin-form (scheme + host, optional trailing / only); path prefixes are rejected at startup. Use Lua paths that start with / so the joined URL is {base}/path. If the Lua URL has a scheme, it is used as-is even when base_url is set. A relative URL with no base_url returns (nil, error) and does not hit the network.

Example
-- Simple GET request
local response = http.get("https://api.example.com/data")
if response.status == 200 then
  print("Success: " .. response.body)
end

-- GET with headers
local headers = {["Authorization"] = "Bearer token123"}
local response = http.get("https://api.example.com/protected", headers)

-- POST with JSON body
local body = json.encode({key = "value"})
local headers = {["Content-Type"] = "application/json"}
local response = http.post("https://api.example.com/create", body, headers)

-- Generic request
local response = http.request("PUT", "https://api.example.com/update", body, headers)
JSON Service

The JSON service provides JSON encoding and decoding functionality.

Functions
  • json.encode(value) - Encode a Lua value to JSON string

    • Returns: json_string or (nil, error)
  • json.decode(json_string) - Decode a JSON string to a Lua value

    • Returns: value or (nil, error)
Example
-- Encode to JSON
local obj = {
  name = "Alice",
  age = 30,
  roles = {"admin", "user"}
}
local jsonStr = json.encode(obj)
-- Result: '{"name":"Alice","age":30,"roles":["admin","user"]}'

-- Decode from JSON
local data = json.decode('{"key":"value","num":42}')
print(data.key)  -- "value"
print(data.num)  -- 42

-- Round-trip
local original = {test = "data"}
local encoded = json.encode(original)
local decoded = json.decode(encoded)
Base64 Service

The base64 service provides standard base64 encoding and decoding.

Functions
  • base64.encode(string) - Encode a string with standard base64

    • Returns: encoded_string
  • base64.decode(string) - Decode a standard base64 string

    • Returns: decoded_string or (nil, error)
Example
local encoded = base64.encode(json.encode({identity = {org_id = "org-1"}}))
local headers = {["x-rh-identity"] = encoded}
local response = http.get("https://export-compliance.example.internal/v1/compliance", headers)
Config Service

The Config service provides access to configuration values passed to the LuaDataSource.

Functions
  • config.get(key, [default]) - Get a configuration value

    • Returns: value or default if not found
  • config.has(key) - Check if a configuration key exists

    • Returns: bool
  • config.keys() - Get all configuration keys

    • Returns: table (array of strings)
Example
-- Get config values
local apiKey = config.get("api_key")
local timeout = config.get("timeout", 30)  -- with default

-- Check if key exists
if config.has("feature_flag") then
  -- use the feature
end

-- List all keys
local keys = config.keys()
for i, key in ipairs(keys) do
  print(key .. " = " .. tostring(config.get(key)))
end

Type Conversions

Go to Lua
  • string → lua.LString
  • int, int64, float64 → lua.LNumber
  • bool → lua.LBool
  • map[string]interface{} → Lua table (object)
  • []interface{} → Lua table (array)
  • nil → lua.LNil
Lua to Go
  • lua.LString → string
  • lua.LNumber → float64
  • lua.LBool → bool
  • Lua table (with integer keys 1..N) → []interface{}
  • Lua table (with string keys) → map[string]interface{}
  • lua.LNil → nil

Thread Safety

Each service instance can be registered to multiple Lua states. However, Lua states themselves are not thread-safe. The LuaDataSource creates a new Lua state for each request, ensuring thread safety.

Configuration

HTTP Service
// Simple usage with a pre-configured HTTP client (must not be nil)
client := &http.Client{Timeout: 30 * time.Second}
httpService, err := lua.NewHTTPService(ctx, client)

// Relative Lua URLs resolve against base_url (optional)
httpService, err := lua.NewHTTPService(ctx, client,
    lua.WithBaseURL("https://entitlements.internal.example.com"),
)

// With request options (per-request hooks applied before sending)
httpService, err := lua.NewHTTPService(ctx, client,
    lua.WithRequestOptions(func(req *http.Request) error {
        req.Header.Set("X-Tenant-ID", tenantFromContext(ctx))
        return nil
    }),
)
Request Options

The RequestOptions function allows you to modify HTTP requests before they are sent. This is useful for:

  • Adding authentication headers
  • Modifying URLs (e.g., adding query parameters)
  • Setting custom headers
  • Implementing request signing

Example: Adding Authentication

requestOptions := func(req *http.Request) error {
    req.Header.Set("Authorization", "Bearer secret-token")
    return nil
}

Example: Adding Query Parameters

requestOptions := func(req *http.Request) error {
    q := req.URL.Query()
    q.Add("api_key", "secret")
    q.Add("tenant", "acme-corp")
    req.URL.RawQuery = q.Encode()
    return nil
}
Config Service

The Config Service uses a ConfigSource interface to retrieve configuration values:

// Simple in-memory configuration
configSource := lua.NewMapConfigSource(map[string]interface{}{
    "api_key": "secret",
    "timeout": 60,
    "enabled": true,
})
configService := lua.NewConfigService(configSource)
Custom Config Sources

You can implement your own ConfigSource to back configuration with environment variables, files, remote services, etc:

type ConfigSource interface {
    // Get retrieves a configuration value by key
    // Returns the value and true if found, or nil and false if not found
    Get(key string) (interface{}, bool)
    
    // Keys returns all available configuration keys
    Keys() []string
}

Example: Environment Variable Config Source

type EnvConfigSource struct{}

func (e *EnvConfigSource) Get(key string) (interface{}, bool) {
    val, ok := os.LookupEnv(key)
    return val, ok
}

func (e *EnvConfigSource) Keys() []string {
    // Return all env var names
    return []string{} // implementation depends on needs
}

configService := lua.NewConfigService(&EnvConfigSource{})
JSON Service
jsonService := lua.NewJSONService()  // no configuration needed

Error Handling

Services follow Lua's convention of returning (result, error) tuples:

local result, err = http.get("https://example.com")
if result == nil then
  print("Error: " .. err)
else
  print("Success: " .. result.body)
end

Security Considerations

  1. HTTP Timeout: The HTTP service has a configurable timeout to prevent long-running requests
  2. No File System Access: Services don't provide file system access
  3. Sandboxed Execution: Each Lua script runs in its own isolated state
  4. No Subprocess Execution: Services don't allow executing system commands

Best Practices

  1. Handle Errors: Always check for errors when calling service functions
  2. Use Timeouts: Configure appropriate HTTP timeouts for your use case
  3. Validate Inputs: Validate data before encoding to JSON or making HTTP requests
  4. Cache Config: Store frequently accessed config values in local variables
  5. Clean JSON: Use json.encode/decode for reliable serialization

Example: Complete LuaDataSource Script

function fetch(input)
  -- Get configuration
  local apiEndpoint = config.get("api_endpoint")
  local apiKey = config.get("api_key")
  
  -- Access input data
  local subject = input.subject.subject
  
  -- Make HTTP request
  local headers = {
    ["Authorization"] = "Bearer " .. apiKey,
    ["Content-Type"] = "application/json"
  }
  
  local response = http.get(apiEndpoint .. "/user/" .. subject, headers)
  
  if response.status ~= 200 then
    return nil  -- Data source has nothing to contribute
  end
  
  -- Parse and enhance response
  local userData = json.decode(response.body)
  userData.fetched_at = os.time()
  
  -- Return result
  return {
    data = json.encode(userData),
    content_type = "application/json"
  }
end

function fetch_cache_key(input)
  -- Only cache based on subject
  return {
    subject = {
      subject = input.subject.subject
    }
  }
end

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CompileScript added in v0.2.0

func CompileScript(source string, name string) (*lua.FunctionProto, error)

CompileScript parses and compiles a Lua script to bytecode. The returned lua.FunctionProto is immutable and safe to share across goroutines and LState instances.

func GoToLua

func GoToLua(L *lua.LState, value any) lua.LValue

GoToLua converts a Go value to a Lua value

func LoadProto added in v0.2.0

func LoadProto(L *lua.LState, proto *lua.FunctionProto) error

LoadProto loads a pre-compiled lua.FunctionProto into an LState and executes its top-level chunk, which typically defines global functions.

func LuaToGo

func LuaToGo(lv lua.LValue) interface{}

LuaToGo converts a Lua value to a Go value

func ValidateFunction added in v0.2.0

func ValidateFunction(proto *lua.FunctionProto, functionName string) error

ValidateFunction loads a pre-compiled script into a temporary LState and verifies that executing it defines a global function with the given name.

Types

type Base64Service added in v0.9.0

type Base64Service struct{}

Base64Service provides base64 encoding/decoding to Lua scripts.

func NewBase64Service added in v0.9.0

func NewBase64Service() *Base64Service

NewBase64Service creates a new base64 service.

func (*Base64Service) Register added in v0.9.0

func (s *Base64Service) Register(L *lua.LState)

Register adds the base64 service to the Lua state. Usage in Lua:

local encoded = base64.encode("hello")
local decoded, err = base64.decode(encoded)

type ConfigService

type ConfigService struct {
	// contains filtered or unexported fields
}

ConfigService provides access to configuration values in Lua scripts

func NewConfigService

func NewConfigService(source ConfigSource) *ConfigService

NewConfigService creates a new config service with the given configuration source

func (*ConfigService) Register

func (s *ConfigService) Register(L *lua.LState)

Register adds the config service to the Lua state Usage in Lua:

local value = config.get("key")
local value = config.get("key", "default_value")
local exists = config.has("key")

type ConfigSource

type ConfigSource interface {
	// Get retrieves a configuration value by key
	// Returns the value and true if found, or nil and false if not found
	Get(key string) (any, bool)

	// Keys returns all available configuration keys
	Keys() []string
}

ConfigSource is an interface for retrieving configuration values Implementations can back this with environment variables, config files, etc.

func NewMapConfigSource

func NewMapConfigSource(values map[string]any) ConfigSource

NewMapConfigSource creates a ConfigSource backed by a map

type HTTPService

type HTTPService struct {
	// contains filtered or unexported fields
}

HTTPService provides HTTP client functionality to Lua scripts.

func NewHTTPService

func NewHTTPService(ctx context.Context, client *http.Client, opts ...HTTPServiceOption) (*HTTPService, error)

NewHTTPService creates a new HTTP service. ctx is required and propagated to every outgoing request, enabling cancellation, tracing, and request-ID propagation. client is the fully-configured HTTP client (auth, timeout, transport already set) and must not be nil. Optional settings are provided via HTTPServiceOption.

func (*HTTPService) Register

func (s *HTTPService) Register(L *lua.LState)

Register adds the HTTP service to the Lua state Usage in Lua:

local response = http.get("https://api.example.com/data")
local response = http.post("https://api.example.com/data", "request body", {["Content-Type"] = "application/json"})

type HTTPServiceOption

type HTTPServiceOption func(*httpServiceConfig)

HTTPServiceOption configures optional settings for NewHTTPService.

func WithBaseURL added in v0.10.0

func WithBaseURL(base string) HTTPServiceOption

WithBaseURL sets an origin-form base (scheme + host, optional trailing slash only) that relative Lua URLs resolve against. Empty or omitted preserves absolute-URL-only behavior. Path, query, and fragment components are rejected.

func WithRequestOptions

func WithRequestOptions(ro RequestOptions) HTTPServiceOption

WithRequestOptions sets a function that processes requests before sending.

type JSONService

type JSONService struct{}

JSONService provides JSON encoding/decoding functionality to Lua scripts

func NewJSONService

func NewJSONService() *JSONService

NewJSONService creates a new JSON service

func (*JSONService) Register

func (s *JSONService) Register(L *lua.LState)

Register adds the JSON service to the Lua state Usage in Lua:

local obj = json.decode('{"key": "value"}')
local str = json.encode({key = "value"})

type MapConfigSource

type MapConfigSource struct {
	// contains filtered or unexported fields
}

MapConfigSource is a simple in-memory implementation of ConfigSource

func (*MapConfigSource) Get

func (m *MapConfigSource) Get(key string) (any, bool)

Get retrieves a value from the map

func (*MapConfigSource) Keys

func (m *MapConfigSource) Keys() []string

Keys returns all keys in the map

type RequestOptions

type RequestOptions func(*http.Request) error

RequestOptions is a function that can modify a request before it is sent. This can be used to add authentication headers, modify URLs, etc.

type URLService added in v0.7.0

type URLService struct{}

URLService provides URL encoding/decoding functionality to Lua scripts

func NewURLService added in v0.7.0

func NewURLService() *URLService

NewURLService creates a new URL service

func (*URLService) Register added in v0.7.0

func (s *URLService) Register(L *lua.LState)

Register adds the URL service to the Lua state Usage in Lua:

local encoded = url.encode("/C=US/ST=North Carolina")

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL