Skip to main content

Client Configuration

Detailed guide to configuring the Cocobase client.

Table of Contents

Basic Configuration

Minimal Configuration

The simplest way to create a client:

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
})

This uses default values for all other options.

Full Configuration

import (
"net/http"
"time"

"github.com/lordace-coder/cocobase-go/cocobase"
"github.com/lordace-coder/cocobase-go/storage"
)

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
BaseURL: "https://api.cocobase.io",
HTTPClient: &http.Client{
Timeout: 30 * time.Second,
},
Storage: storage.NewMemoryStorage(),
})

Configuration Options

Config Structure

type Config struct {
APIKey string // Required: Your API key
BaseURL string // Optional: API base URL
HTTPClient *http.Client // Optional: Custom HTTP client
Storage Storage // Optional: Token storage
}

Default Values

If not specified, these defaults are used:

const (
DefaultBaseURL = "http://localhost:3000"
DefaultTimeout = 30 * time.Second
)

Custom HTTP Client

Basic Custom Client

httpClient := &http.Client{
Timeout: 60 * time.Second,
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

With Custom Transport

httpClient := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
},
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

With Proxy

proxyURL, _ := url.Parse("http://proxy.example.com:8080")

httpClient := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

With TLS Configuration

import "crypto/tls"

tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
}

httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

With Logging

type LoggingTransport struct {
Transport http.RoundTripper
}

func (t *LoggingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
log.Printf("Request: %s %s", req.Method, req.URL)

resp, err := t.Transport.RoundTrip(req)

if err != nil {
log.Printf("Error: %v", err)
} else {
log.Printf("Response: %d", resp.StatusCode)
}

return resp, err
}

httpClient := &http.Client{
Transport: &LoggingTransport{
Transport: http.DefaultTransport,
},
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

Base URL Configuration

Development

client := cocobase.NewClient(cocobase.Config{
APIKey: "dev-api-key",
BaseURL: "http://localhost:3000",
})

Production

client := cocobase.NewClient(cocobase.Config{
APIKey: "prod-api-key",
BaseURL: "https://api.cocobase.io",
})

Custom Domain

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
BaseURL: "https://api.yourdomain.com",
})

Storage Configuration

No Storage (Default)

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
// Storage: nil (default)
})

Tokens are not persisted and lost on restart.

Memory Storage

import "github.com/lordace-coder/cocobase-go/storage"

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
Storage: storage.NewMemoryStorage(),
})

Tokens persist in memory until application exits.

File Storage

import "github.com/lordace-coder/cocobase-go/storage"

store, err := storage.NewFileStorage(".cocobase/auth.json")
if err != nil {
log.Fatal(err)
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
Storage: store,
})

Tokens persist to disk across application restarts.

Custom Storage

See Storage Guide for implementing custom storage.

Environment-Based Configuration

Using Environment Variables

import "os"

client := cocobase.NewClient(cocobase.Config{
APIKey: os.Getenv("COCOBASE_API_KEY"),
BaseURL: os.Getenv("COCOBASE_BASE_URL"),
})

With .env Files

import (
"os"

"github.com/joho/godotenv"
)

func init() {
godotenv.Load()
}

func main() {
client := cocobase.NewClient(cocobase.Config{
APIKey: os.Getenv("COCOBASE_API_KEY"),
BaseURL: os.Getenv("COCOBASE_BASE_URL"),
})
}

.env file:

COCOBASE_API_KEY=your-api-key
COCOBASE_BASE_URL=https://api.cocobase.io

Environment-Specific Configuration

func getConfig() cocobase.Config {
env := os.Getenv("ENV")

switch env {
case "production":
return cocobase.Config{
APIKey: os.Getenv("PROD_API_KEY"),
BaseURL: "https://api.cocobase.io",
}
case "staging":
return cocobase.Config{
APIKey: os.Getenv("STAGING_API_KEY"),
BaseURL: "https://staging-api.cocobase.io",
}
default:
return cocobase.Config{
APIKey: os.Getenv("DEV_API_KEY"),
BaseURL: "http://localhost:3000",
}
}
}

client := cocobase.NewClient(getConfig())

Advanced Configurations

Singleton Pattern

package main

import (
"sync"

"github.com/lordace-coder/cocobase-go/cocobase"
)

var (
client *cocobase.Client
once sync.Once
)

func GetClient() *cocobase.Client {
once.Do(func() {
client = cocobase.NewClient(cocobase.Config{
APIKey: os.Getenv("COCOBASE_API_KEY"),
})
})

return client
}

// Usage
func main() {
client := GetClient()
// Use client
}

Configuration from File

import (
"encoding/json"
"os"
)

type AppConfig struct {
CocobaseAPIKey string `json:"cocobase_api_key"`
CocobaseURL string `json:"cocobase_url"`
}

func loadConfig(path string) (*AppConfig, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()

var config AppConfig
if err := json.NewDecoder(file).Decode(&config); err != nil {
return nil, err
}

return &config, nil
}

func main() {
config, err := loadConfig("config.json")
if err != nil {
log.Fatal(err)
}

client := cocobase.NewClient(cocobase.Config{
APIKey: config.CocobaseAPIKey,
BaseURL: config.CocobaseURL,
})
}

Multi-Tenant Configuration

type TenantClient struct {
clients map[string]*cocobase.Client
mu sync.RWMutex
}

func NewTenantClient() *TenantClient {
return &TenantClient{
clients: make(map[string]*cocobase.Client),
}
}

func (tc *TenantClient) GetClient(tenantID string) *cocobase.Client {
tc.mu.RLock()
client, exists := tc.clients[tenantID]
tc.mu.RUnlock()

if exists {
return client
}

tc.mu.Lock()
defer tc.mu.Unlock()

// Double-check after acquiring write lock
if client, exists := tc.clients[tenantID]; exists {
return client
}

// Create new client for tenant
apiKey := getTenantAPIKey(tenantID)
client = cocobase.NewClient(cocobase.Config{
APIKey: apiKey,
})

tc.clients[tenantID] = client
return client
}

// Usage
tenantClient := NewTenantClient()
client1 := tenantClient.GetClient("tenant-1")
client2 := tenantClient.GetClient("tenant-2")

With Retry Transport

type RetryTransport struct {
Transport http.RoundTripper
MaxRetries int
}

func (t *RetryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
var resp *http.Response
var err error

for i := 0; i <= t.MaxRetries; i++ {
resp, err = t.Transport.RoundTrip(req)

if err == nil && resp.StatusCode < 500 {
return resp, nil
}

if i < t.MaxRetries {
time.Sleep(time.Duration(i+1) * time.Second)
}
}

return resp, err
}

httpClient := &http.Client{
Transport: &RetryTransport{
Transport: http.DefaultTransport,
MaxRetries: 3,
},
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

With Metrics Collection

type MetricsTransport struct {
Transport http.RoundTripper
Metrics *Metrics
}

type Metrics struct {
RequestCount int64
ErrorCount int64
TotalDuration time.Duration
mu sync.Mutex
}

func (t *MetricsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
start := time.Now()

resp, err := t.Transport.RoundTrip(req)

duration := time.Since(start)

t.Metrics.mu.Lock()
t.Metrics.RequestCount++
t.Metrics.TotalDuration += duration
if err != nil || (resp != nil && resp.StatusCode >= 400) {
t.Metrics.ErrorCount++
}
t.Metrics.mu.Unlock()

return resp, err
}

metrics := &Metrics{}

httpClient := &http.Client{
Transport: &MetricsTransport{
Transport: http.DefaultTransport,
Metrics: metrics,
},
}

client := cocobase.NewClient(cocobase.Config{
APIKey: "your-api-key",
HTTPClient: httpClient,
})

// Check metrics
fmt.Printf("Requests: %d, Errors: %d, Avg Duration: %v\n",
metrics.RequestCount,
metrics.ErrorCount,
metrics.TotalDuration/time.Duration(metrics.RequestCount))

Configuration Validation

func validateConfig(config cocobase.Config) error {
if config.APIKey == "" {
return fmt.Errorf("API key is required")
}

if config.BaseURL != "" {
if _, err := url.Parse(config.BaseURL); err != nil {
return fmt.Errorf("invalid base URL: %w", err)
}
}

return nil
}

// Usage
config := cocobase.Config{
APIKey: os.Getenv("COCOBASE_API_KEY"),
BaseURL: os.Getenv("COCOBASE_BASE_URL"),
}

if err := validateConfig(config); err != nil {
log.Fatal(err)
}

client := cocobase.NewClient(config)

Best Practices

1. Store API Keys Securely

// Good: Environment variables
apiKey := os.Getenv("COCOBASE_API_KEY")

// Bad: Hard-coded
apiKey := "hardcoded-key"

2. Use Appropriate Timeouts

// Good: Custom timeout based on needs
httpClient := &http.Client{
Timeout: 30 * time.Second,
}

3. Enable Storage in Production

// Good: Persistent storage
store, _ := storage.NewFileStorage(".cocobase/auth.json")

client := cocobase.NewClient(cocobase.Config{
APIKey: apiKey,
Storage: store,
})

4. Reuse Client Instances

// Good: Single instance
var client = cocobase.NewClient(config)

// Bad: Creating new clients
func doSomething() {
client := cocobase.NewClient(config) // Don't do this
}

5. Use HTTPS in Production

// Good: HTTPS
BaseURL: "https://api.cocobase.io"

// Bad: HTTP in production
// BaseURL: "http://api.cocobase.io"

Previous: Getting Started | Next: Document Operations