Builder Pattern
The SDK uses a fluent builder pattern for constructing service instances. This provides type-safe configuration with clear validation.
Basic Builder
svc , err := cliproxy . NewBuilder ().
WithConfig ( cfg ).
WithConfigPath ( "config.yaml" ).
Build ()
Required Configuration
Two fields are required :
. WithConfig ( cfg ) // Configuration object
. WithConfigPath ( path ) // Config file path for watching
If either is missing, Build() returns an error:
svc , err := cliproxy . NewBuilder ().
WithConfig ( cfg ).
Build ()
// Error: "cliproxy: configuration path is required"
Builder Options
Configuration Methods
WithConfig
Sets the configuration instance:
cfg , err := config . LoadConfig ( "config.yaml" )
if err != nil {
return err
}
builder . WithConfig ( cfg )
WithConfigPath
Sets the file path for configuration watching:
builder . WithConfigPath ( "/etc/myapp/config.yaml" )
When the file changes, the configuration is automatically reloaded.
Authentication Providers
WithTokenClientProvider
Customize how token-backed clients are loaded:
type CustomTokenProvider struct {}
func ( p * CustomTokenProvider ) Load ( ctx context . Context , cfg * config . Config ) ( * cliproxy . TokenClientResult , error ) {
// Custom token loading logic
return & cliproxy . TokenClientResult {
SuccessfulAuthed : 5 ,
}, nil
}
builder . WithTokenClientProvider ( & CustomTokenProvider {})
WithAPIKeyClientProvider
Customize API key client loading:
type CustomAPIKeyProvider struct {}
func ( p * CustomAPIKeyProvider ) Load ( ctx context . Context , cfg * config . Config ) ( * cliproxy . APIKeyClientResult , error ) {
// Load API keys from custom source
return & cliproxy . APIKeyClientResult {
GeminiKeyCount : 3 ,
ClaudeKeyCount : 2 ,
}, nil
}
builder . WithAPIKeyClientProvider ( & CustomAPIKeyProvider {})
Authentication Managers
WithAuthManager
Override the legacy authentication manager:
import sdkAuth " github.com/router-for-me/CLIProxyAPI/v6/sdk/auth "
authManager := sdkAuth . NewManager (
sdkAuth . GetTokenStore (),
sdkAuth . NewGeminiAuthenticator (),
sdkAuth . NewClaudeAuthenticator (),
)
builder . WithAuthManager ( authManager )
WithCoreAuthManager
Customize the core authentication manager:
import coreauth " github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth "
tokenStore := sdkAuth . GetTokenStore ()
selector := & coreauth . RoundRobinSelector {}
coreManager := coreauth . NewManager ( tokenStore , selector , nil )
builder . WithCoreAuthManager ( coreManager )
WithRequestAccessManager
Set the request access manager for authentication:
import sdkaccess " github.com/router-for-me/CLIProxyAPI/v6/sdk/access "
accessManager := sdkaccess . NewManager ()
// Register custom providers
sdkaccess . RegisterProvider ( "custom" , myProvider )
accessManager . SetProviders ( sdkaccess . RegisteredProviders ())
builder . WithRequestAccessManager ( accessManager )
File Watching
WithWatcherFactory
Customize configuration and auth file watching:
import " github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy "
factory := func ( configPath , authDir string , reload func ( * config . Config )) ( * cliproxy . WatcherWrapper , error ) {
// Create custom watcher
return & cliproxy . WatcherWrapper {
// ... implementation
}, nil
}
builder . WithWatcherFactory ( factory )
Server Options
WithServerOptions
Add HTTP server configuration options:
import (
" github.com/gin-gonic/gin "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/api "
)
builder . WithServerOptions (
// Add custom middleware
api . WithMiddleware ( func ( c * gin . Context ) {
c . Header ( "X-Custom-Header" , "value" )
c . Next ()
}),
// Add custom request logger
api . WithRequestLoggerFactory ( func ( cfg * config . Config , cfgPath string ) logging . RequestLogger {
return myCustomLogger
}),
)
WithLocalManagementPassword
Set a password for localhost management endpoints:
builder . WithLocalManagementPassword ( "secure-password-123" )
This restricts management API access:
# Without password - 401 Unauthorized
curl http://localhost:8080/v1/management/models
# With password - Success
curl -H "Authorization: Bearer secure-password-123" \
http://localhost:8080/v1/management/models
Management endpoints are only accessible from localhost (127.0.0.1) for security.
WithPostAuthHook
Register a hook called after auth creation but before persistence:
import coreauth " github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth "
hook := func ( ctx context . Context , auth * coreauth . Auth ) error {
// Inject custom metadata
if auth . Metadata == nil {
auth . Metadata = make ( map [ string ] any )
}
auth . Metadata [ "custom_field" ] = "value"
// Access request info if available
if reqInfo := coreauth . GetRequestInfo ( ctx ); reqInfo != nil {
auth . Metadata [ "request_ip" ] = reqInfo . Headers . Get ( "X-Forwarded-For" )
}
return nil
}
builder . WithPostAuthHook ( hook )
Lifecycle Hooks
Hooks allow you to execute custom code during service lifecycle events.
OnBeforeStart
Called before the service starts, allowing configuration modifications:
hooks := cliproxy . Hooks {
OnBeforeStart : func ( cfg * config . Config ) {
// Modify configuration
cfg . LogLevel = "debug"
// Add runtime values
if os . Getenv ( "PROXY_URL" ) != "" {
cfg . ProxyURL = os . Getenv ( "PROXY_URL" )
}
// Validate custom requirements
if cfg . Port < 1024 {
log . Warn ( "Using privileged port, ensure proper permissions" )
}
},
}
builder . WithHooks ( hooks )
OnAfterStart
Called after successful startup, providing access to the running service:
hooks := cliproxy . Hooks {
OnAfterStart : func ( svc * cliproxy . Service ) {
// Register usage tracking
svc . RegisterUsagePlugin ( myUsagePlugin )
// Register custom models
models := [] * cliproxy . ModelInfo {
{
ID : "custom-model-1" ,
Object : "model" ,
Type : "custom" ,
DisplayName : "Custom Model 1" ,
},
}
cliproxy . GlobalModelRegistry (). RegisterClient (
"custom-provider" ,
"custom" ,
models ,
)
// Start background tasks
go monitorServiceHealth ( svc )
},
}
builder . WithHooks ( hooks )
Complete Hooks Example
package main
import (
" context "
" fmt "
" time "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/config "
)
func main () {
cfg , _ := config . LoadConfig ( "config.yaml" )
hooks := cliproxy . Hooks {
OnBeforeStart : func ( cfg * config . Config ) {
fmt . Println ( "==> Preparing service..." )
// Apply environment overrides
cfg . LogLevel = "info"
// Log configuration
fmt . Printf ( "Host: %s : %d \n " , cfg . Host , cfg . Port )
fmt . Printf ( "Auth Dir: %s \n " , cfg . AuthDir )
},
OnAfterStart : func ( svc * cliproxy . Service ) {
fmt . Println ( "==> Service started successfully" )
fmt . Printf ( "API endpoint: http:// %s : %d \n " , cfg . Host , cfg . Port )
// Start health check
go func () {
ticker := time . NewTicker ( 30 * time . Second )
defer ticker . Stop ()
for range ticker . C {
// Check service health
fmt . Println ( "Health check: OK" )
}
}()
},
}
svc , err := cliproxy . NewBuilder ().
WithConfig ( cfg ).
WithConfigPath ( "config.yaml" ).
WithHooks ( hooks ).
Build ()
if err != nil {
panic ( err )
}
svc . Run ( context . Background ())
}
Complete Builder Example
Here’s a comprehensive example using multiple builder options:
package main
import (
" context "
" fmt "
" os "
" github.com/gin-gonic/gin "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/api "
sdkaccess " github.com/router-for-me/CLIProxyAPI/v6/sdk/access "
sdkAuth " github.com/router-for-me/CLIProxyAPI/v6/sdk/auth "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy "
coreauth " github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/config "
" github.com/router-for-me/CLIProxyAPI/v6/sdk/logging "
)
func main () {
// Load configuration
cfg , err := config . LoadConfig ( "config.yaml" )
if err != nil {
fmt . Fprintf ( os . Stderr , "Config error: %v \n " , err )
os . Exit ( 1 )
}
// Set up auth manager
tokenStore := sdkAuth . GetTokenStore ()
if dirSetter , ok := tokenStore .( interface { SetBaseDir ( string ) }); ok {
dirSetter . SetBaseDir ( cfg . AuthDir )
}
// Create core auth manager with custom selector
selector := & coreauth . RoundRobinSelector {}
coreManager := coreauth . NewManager ( tokenStore , selector , nil )
// Set up access manager
accessManager := sdkaccess . NewManager ()
accessManager . SetProviders ( sdkaccess . RegisteredProviders ())
// Define lifecycle hooks
hooks := cliproxy . Hooks {
OnBeforeStart : func ( cfg * config . Config ) {
fmt . Println ( "Initializing service..." )
},
OnAfterStart : func ( svc * cliproxy . Service ) {
fmt . Printf ( "Service ready at http:// %s : %d \n " , cfg . Host , cfg . Port )
},
}
// Post-auth hook to add metadata
postAuthHook := func ( ctx context . Context , auth * coreauth . Auth ) error {
if auth . Metadata == nil {
auth . Metadata = make ( map [ string ] any )
}
auth . Metadata [ "app_version" ] = "1.0.0"
return nil
}
// Build the service
svc , err := cliproxy . NewBuilder ().
WithConfig ( cfg ).
WithConfigPath ( "config.yaml" ).
WithCoreAuthManager ( coreManager ).
WithRequestAccessManager ( accessManager ).
WithHooks ( hooks ).
WithLocalManagementPassword ( "admin-password" ).
WithPostAuthHook ( postAuthHook ).
WithServerOptions (
api . WithMiddleware ( func ( c * gin . Context ) {
c . Header ( "X-Powered-By" , "MyApp" )
c . Next ()
}),
api . WithRequestLoggerFactory ( func ( cfg * config . Config , cfgPath string ) logging . RequestLogger {
return logging . NewFileRequestLogger ( "logs" , "./" )
}),
).
Build ()
if err != nil {
fmt . Fprintf ( os . Stderr , "Build error: %v \n " , err )
os . Exit ( 1 )
}
// Run the service
ctx := context . Background ()
if err := svc . Run ( ctx ); err != nil {
fmt . Fprintf ( os . Stderr , "Runtime error: %v \n " , err )
os . Exit ( 1 )
}
}
Service Management
Starting the Service
ctx := context . Background ()
err := svc . Run ( ctx )
The Run method:
Starts the HTTP server
Initializes authentication
Starts file watchers
Blocks until context is cancelled
Stopping the Service
// Cancel the context to initiate shutdown
cancel ()
// Or call Shutdown explicitly with timeout
shutdownCtx , cancel := context . WithTimeout ( context . Background (), 30 * time . Second )
defer cancel ()
err := svc . Shutdown ( shutdownCtx )
The Shutdown method:
Stops accepting new requests
Completes in-flight requests
Stops file watchers
Cleans up resources
Is idempotent (safe to call multiple times)
Next Steps
Advanced Features Learn about custom executors and translators
Access Providers Implement custom authentication
File Watching Understand config and auth file watching
Usage Tracking Monitor API usage and consumption