Skip to content

switcherapi/switcher-client-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Switcher Client SDK
A Go SDK for Switcher API

Master CI Quality Gate Status Known Vulnerabilities Go Report Card Go Status License: MIT Slack: Switcher-HQ


Switcher API: Go Client: Cloud-based Feature Flag API


Table of Contents


About

The Switcher Client SDK for Go provides integration with Switcher-API, enabling feature flag management in Go applications.

Features marked as Under development are part of the current SDK roadmap and may not be available in the repository yet.

Key Features

  • Clean & Maintainable: Simple package-level access with an instance-based core
  • Local Mode: Offline execution using snapshot files from your Switcher-API domain
  • Silent Mode: Hybrid configuration with automatic fallback for connectivity issues
  • Built-in Testing Helpers (Under development): Test-oriented mocking support adapted for Go
  • Zero Latency: Local snapshot execution for high-performance scenarios
  • Secure: Regex protections and configurable remote transport settings
  • Monitoring: Execution logging, caching, and error notification hooks

Quick Start

Get up and running in just a few lines of code:

package main

import (
	"fmt"

	"github.com/switcherapi/switcher-client-go"
)

func main() {
	client.BuildContext(client.Context{
		Domain:      "My Domain",
		URL:         "https://api.switcherapi.com",
		APIKey:      "[YOUR_API_KEY]",
		Component:   "MyApp",
		Environment: "default",
	})

	switcher := client.GetSwitcher("FEATURE_TOGGLE")
	enabled, err := switcher.IsOn()
	if err != nil {
		panic(err)
	}

	if enabled {
		fmt.Println("Feature is enabled!")
	}
}

Installation

Install the Switcher Client SDK:

go get github.com/switcherapi/switcher-client-go

System Requirements

  • Go: 1.25+ (targeting 1.25.x and 1.26.x)
  • Operating System: Cross-platform (Windows, macOS, Linux)

Configuration

Basic Setup

Initialize the Switcher Client with your domain configuration:

package main

import (
	"github.com/switcherapi/switcher-client-go"
)

func main() {
	client.BuildContext(client.Context{
		Domain:      "My Domain",                	// Your Switcher domain name
		URL:         "https://api.switcherapi.com", // Switcher-API endpoint (optional)
		APIKey:      "[YOUR_API_KEY]",           	// Your component's API key (optional)
		Component:   "MyApp",                    	// Your application name (optional)
		Environment: "default",                  	// Environment ("default" for production)
	})

	switcher := client.GetSwitcher("FEATURE_LOGIN_V2")
	_ = switcher
}

Configuration Parameters

Parameter Required Description Default
Domain Your Switcher domain name -
URL Switcher-API endpoint https://api.switcherapi.com
APIKey API key for your component -
Component Your application identifier -
Environment Target environment default

Advanced Configuration

Enable additional features like local mode, silent mode, and transport options:

package main

import (
	"time"

	"github.com/switcherapi/switcher-client-go"
)

func main() {
	client.BuildContext(client.Context{
		Domain:      "My Domain",
		URL:         "https://api.switcherapi.com",
		APIKey:      "[YOUR_API_KEY]",
		Component:   "MyApp",
		Environment: "default",
		Options: client.ContextOptions{
			Local:                      true,
			Logger:                     true,
			Freeze:                     true,
			SnapshotLocation:           "./snapshot/",
			SnapshotAutoUpdateInterval: 30 * time.Second,
			SilentMode:                 5 * time.Minute,
			RestrictRelay:              true,
			ThrottleMaxWorkers:         2,
			RegexMaxBlacklist:          10,
			RegexMaxTimeLimit:          100 * time.Millisecond,
			Remote: client.RemoteOptions{
				CertPath:       "./certs/ca.pem",
				ConnectTimeout: 300 * time.Millisecond,
				Timeout:        5 * time.Second,
			},
		},
	})

	switcher := client.GetSwitcher("FEATURE_LOGIN_V2")
	_ = switcher
}

Advanced Options Reference

Option Type Description Default
Local bool Use local snapshot files only (zero latency) false
Logger bool Enable logging/caching of feature flag evaluations false
Freeze bool Enable cache-immutability responses for consistent results false
SnapshotLocation string Directory for snapshot files ""
SnapshotAutoUpdateInterval time.Duration Auto-update interval for snapshots 0
SilentMode time.Duration Silent mode retry time before returning to remote mode 0
RestrictRelay bool Enable relay restrictions in local mode true
ThrottleMaxWorkers int Max workers for throttling refresh tasks runtime-defined
RegexMaxBlacklist int Max cached entries for failed regex 100
RegexMaxTimeLimit time.Duration Regex execution time limit 3s
Remote RemoteOptions Remote transport settings RemoteOptions{}

RemoteOptions fields:

Option Type Description Default
CertPath string Path to custom certificate for secure API connections ""
ConnectTimeout time.Duration Max time to establish a remote connection before failing fast 300ms
Timeout time.Duration Max time for remote request/response and idle connection reuse 5s

Note: lower remote connect timeouts help silent mode fall back faster when the upstream is unavailable.

Security Features

  • ReDoS Protection (Under development): Regex safety features with bounded execution time
  • Time Limits: Configurable timeouts for regex and remote operations
  • Certificate Support: Custom certificates for secure API connections

Usage Examples

Basic Feature Flag Checking

The simplest way to check if a feature is enabled:

switcher := client.GetSwitcher("FEATURE_LOGIN_V2")

enabled, err := switcher.IsOn()
if err != nil {
	panic(err)
}

if enabled {
	newLogin()
} else {
	legacyLogin()
}

Detailed Response Information

Get comprehensive information about the feature flag evaluation:

response, err := client.GetSwitcher("FEATURE_LOGIN_V2").IsOnWithDetails()
if err != nil {
	panic(err)
}

fmt.Printf("Feature enabled: %v\n", response.Result)
fmt.Printf("Reason: %s\n", response.Reason)
fmt.Printf("Metadata: %#v\n", response.Metadata)

Must-variant with default response:

Simpified response handling with default values when errors occur:

feature := client.GetSwitcher("FEATURE_LOGIN_V2")

enabled = feature.IsOnOrDefault(false)
response := feature.IsOnWithDetailsOrDefault(ResultDetail{
	Result: false,
	Reason: "default",
})

Use the async error channel for non-blocking error handling:

client.SubscribeNotifyError(func(err error) {
	fmt.Printf("Switcher Error: %v\n", err)
})

Strategy-Based Feature Flags

Method 1: Prepare and Execute

Load validation data separately, useful for complex applications:

prepared := client.GetSwitcher("").
	CheckValue("USER_123")

if err := prepared.Prepare("USER_FEATURE"); err != nil {
	panic(err)
}

enabled, err := prepared.IsOn()
if err != nil {
	panic(err)
}

if enabled {
	enableUserFeature()
}

Method 2: All-in-One Execution

Chain multiple validation strategies for comprehensive feature control:

isEnabled, err := client.GetSwitcher("PREMIUM_FEATURES").
	CheckValue("premium_user").
	CheckNetwork("192.168.1.0/24").
	DefaultResult(true).
	Throttle(time.Second).
	IsOn()

if err != nil {
	panic(err)
}

if isEnabled {
	showPremiumDashboard()
}

Error Handling

Subscribe to error notifications for robust error management:

client.SubscribeNotifyError(func(err error) {
	fmt.Printf("Switcher Error: %v\n", err)
})

Advanced Features

Throttling

Throttle implements Stale-While-Revalidate behavior for feature flag evaluations, returning cached results while refreshing in the background. This is ideal for high-traffic scenarios where you want to minimize latency and avoid overwhelming the API with requests.

_, err := client.GetSwitcher("FEATURE01").Throttle(time.Second).IsOn()
if err != nil {
	panic(err)
}

Throttle reuses the latest cached execution for the same switcher key and inputs. It records that cached execution even when ContextOptions.Logger is false, and when Freeze is enabled the cached value stays in place until client.ClearLogger() is called.

switcher := client.GetSwitcher("FEATURE01").Throttle(time.Second)
_, _ = switcher.IsOnWithDetails()

logged := client.GetExecution(switcher)
fmt.Println(logged.Response.Metadata["cached"])

Hybrid Mode

_, err := client.GetSwitcher("FEATURE01").Remote().IsOn()
if err != nil {
	panic(err)
}

Circuit Breaker: Silent Mode

This feature allows you to specify how long the client SDK should attempt to restore connectivity in case of remote API failures.

When the API is unavailable, the SDK will automatically operate in silent mode, evaluating Switchers using a local snapshot. It is important to note that any Switcher Key configured must be able to resolve without external dependencies (e.g., Switcher Relay).

Make sure to configure the scheduled snapshot auto-update to keep the local snapshot up to date with the remote API.

Here is an example - in-memory snapshot with auto-update every 30 seconds:

client.BuildContext(client.Context{
	Domain:      "My Domain",
	URL:         "https://api.switcherapi.com",
	APIKey:      "[YOUR_API_KEY]",
	Component:   "MyApp",
	Options: client.ContextOptions{
		SnapshotAutoUpdateInterval: 30 * time.Second,
		SilentMode:                 5 * time.Minute,
	},
})

Snapshot Management

Loading Snapshots

Load snapshots from the API or local files:

version, err := client.LoadSnapshot(nil)
if err != nil {
	panic(err)
}

fmt.Println(version)
version, err := client.LoadSnapshot(&client.LoadSnapshotOptions{
	FetchRemote: true,
})
if err != nil {
	panic(err)
}

fmt.Println(version)
_, err := client.LoadSnapshot(&client.LoadSnapshotOptions{
	WatchSnapshot: true,
})
if err != nil {
	panic(err)
}

Version Management

Check your current snapshot version:

updated, err := client.CheckSnapshot()
if err != nil {
	panic(err)
}

fmt.Printf("Snapshot updated: %v\n", updated)
fmt.Printf("Current snapshot version: %d\n", client.SnapshotVersion())

Automated Updates

Schedule automatic snapshot updates for zero-latency local mode:

client.ScheduleSnapshotAutoUpdate(time.Minute, func(err error, updated bool) {
	if err != nil {
		fmt.Printf("snapshot update error: %v\n", err)
		return
	}

	if updated {
		fmt.Printf("Snapshot updated to version: %d\n", client.SnapshotVersion())
	}
})

Snapshot Monitoring

err := client.WatchSnapshot(client.WatchSnapshotCallback{
	Success: func() {
		fmt.Println("snapshot loaded successfully")
	},
	Reject: func(err error) {
		fmt.Printf("error loading snapshot: %v\n", err)
	},
})
if err != nil {
	panic(err)
}

Testing & Development

Built-in Mocking (Under development)

The Go SDK provides test-oriented mocking capabilities adapted to Go idioms and safer state ownership.

sdk := client.NewClient(ctx)
sdk.Assume("FEATURE01").True()

enabled, err := sdk.GetSwitcher("FEATURE01").IsOn()
assert.NoError(t, err)
assert.True(t, enabled)
sdk.Assume("FEATURE01").True().
	When(client.StrategyValue, []string{"guest", "admin"}).
	When(client.StrategyNetwork, "10.0.0.3")

enabled, err := sdk.GetSwitcher("FEATURE01").
	CheckValue("guest").
	CheckNetwork("10.0.0.3").
	IsOn()
assert.NoError(t, err)
assert.True(t, enabled)
sdk.Forget("FEATURE01")
sdk.Assume("FEATURE01").False().WithMetadata(map[string]any{
	"message": "Feature is disabled",
})

response, err := sdk.GetSwitcher("FEATURE01").IsOnWithDetails()
assert.NoError(t, err)
assert.Equal(t, false, response.Result)
assert.Equal(t, "Feature is disabled", response.Metadata["message"])

Test Helpers (Under development)

This area is under active development. The helper surface focuses on:

  • explicit test helpers instead of decorators
  • automatic cleanup helpers for tests where useful
  • mock isolation by client instance and, when needed, context.Context

Configuration Validation

Validate your feature flag configuration before deployment:

err := client.CheckSwitchers([]string{
	"FEATURE_LOGIN",
	"FEATURE_DASHBOARD",
	"FEATURE_PAYMENTS",
})
if err != nil {
	fmt.Printf("Configuration error: %v\n", err)
}

This validation helps prevent deployment issues by ensuring all required feature flags are properly set up in your Switcher domain.

Contributing

We welcome contributions to the Switcher Client SDK for Go. If you have suggestions, improvements, or bug fixes, please follow these steps:

  1. Fork the repository.
  2. Create a new branch for your feature or bug fix.
  3. Make your changes and commit them with clear messages.
  4. Submit a pull request detailing your changes and the problem they solve.

Thank you for helping us improve the Switcher Client SDK for Go.

Requirements

  • Go 1.25 or higher
  • A local Switcher API environment or test fixtures for development
  • Standard Go tooling (go test, gofmt)
  • golangci-lint for repository lint checks (make lint-install)

AI Disclaimer

This project was ported from switcherapi/switcher-client-py and adapted for Go using AI-assisted tools. We have thoroughly reviewed and tested all AI-generated contributions to ensure they meet our quality standards and align with our project's goals. We are committed to transparency about our use of AI and will continue to disclose any significant AI contributions in the future.

External contributions from the community are equally valued and will be reviewed with the same standards, regardless of whether they were assisted by AI or not. We encourage all contributors to disclose their use of AI tools in their contributions to maintain transparency and foster trust within our community.

About

[Go] Switcher Client - Go SDK to work with Switcher API - Cloud-based Feature Flag

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Contributors

Languages