Command Palette

Search for a command to run...

Go

Go SDK with goroutines and efficient concurrent processing

Installation & Setup
Required setup and dependencies for Go development

Project Setup

go mod init leakzero-example

go get github.com/google/uuid

export LEAKZERO_API_KEY=your_api_key_here

go run main.go

go.mod

module leakzero-example

go 1.21

require (
    github.com/google/uuid v1.4.0
)

Dockerfile

FROM golang:1.21-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN go build -o leakzero-client main.go

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/

COPY --from=builder /app/leakzero-client .
CMD ["./leakzero-client"]
Go Version: This example requires Go 1.18+ for generics support and improved error handling. The UUID package is the only external dependency.
Quick Start Example
Simple example to get you started with Go

basic_usage.go

package main

import (
	"context"
	"fmt"
	"log"
	"os"
)

func main() {
	client := NewLeakZeroClient(os.Getenv("LEAKZERO_API_KEY"))
	ctx := context.Background()

	result, err := client.RegularSearch(ctx, SearchOptions{
		Field:    "email",
		Value:    "[email protected]",
		RowLimit: 100,
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Found %d records\n", result.TotalResults)
	fmt.Printf("Cost: $%.6f\n", result.Cost)

	for i, record := range result.Data {
		if i >= 5 {
			break
		}
		breach := record["breach_name"]
		date := record["breach_date"]
		fmt.Printf("Breach: %v, Date: %v\n", breach, date)
	}
}
Production ReadyComplete Go Implementation
Full-featured client with concurrency, error handling, and enterprise features

main.go

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/uuid"
)

type SearchOptions struct {
	Field      string                 `json:"field"`
	Value      string                 `json:"value"`
	Option     string                 `json:"option,omitempty"`
	RowLimit   int                    `json:"rowLimit,omitempty"`
	AutoExport map[string]interface{} `json:"autoExport,omitempty"`
}

type SearchResult struct {
	Data           []map[string]interface{} `json:"data"`
	TotalResults   int                      `json:"totalResults"`
	Cost           float64                  `json:"cost"`
	RequestID      string                   `json:"requestId"`
	ProcessingTime int                      `json:"processingTime"`
	Analysis       map[string]interface{}   `json:"analysis,omitempty"`
}

type BalanceResponse struct {
	Balance   float64 `json:"balance"`
	Currency  string  `json:"currency"`
	LastUsage string  `json:"lastUsage"`
}

type UsageStats struct {
	TotalRequests    int     `json:"totalRequests"`
	TotalCost        float64 `json:"totalCost"`
	RequestsToday    int     `json:"requestsToday"`
	CostToday        float64 `json:"costToday"`
	RequestsThisWeek int     `json:"requestsThisWeek"`
	CostThisWeek     float64 `json:"costThisWeek"`
}

type APIError struct {
	Error      string `json:"error"`
	Message    string `json:"message"`
	StatusCode int    `json:"statusCode"`
	RetryAfter int    `json:"retryAfter,omitempty"`
}

func (e *APIError) Error() string {
	return fmt.Sprintf("API Error [%d]: %s - %s", e.StatusCode, e.Error, e.Message)
}

type LeakZeroClient struct {
	APIKey     string
	BaseURL    string
	HTTPClient *http.Client
	Logger     *log.Logger
	MaxRetries int
}

func NewLeakZeroClient(apiKey string, options ...func(*LeakZeroClient)) *LeakZeroClient {
	if apiKey == "" {
		panic("API key is required")
	}

	client := &LeakZeroClient{
		APIKey:  apiKey,
		BaseURL: "https://api.leakzero.io/api/v1",
		HTTPClient: &http.Client{
			Timeout: 120 * time.Second,
		},
		Logger:     log.New(os.Stdout, "[LeakZero] ", log.LstdFlags),
		MaxRetries: 3,
	}

	for _, option := range options {
		option(client)
	}

	return client
}

func WithBaseURL(baseURL string) func(*LeakZeroClient) {
	return func(c *LeakZeroClient) {
		c.BaseURL = strings.TrimSuffix(baseURL, "/")
	}
}

func WithTimeout(timeout time.Duration) func(*LeakZeroClient) {
	return func(c *LeakZeroClient) {
		c.HTTPClient.Timeout = timeout
	}
}

func WithMaxRetries(maxRetries int) func(*LeakZeroClient) {
	return func(c *LeakZeroClient) {
		c.MaxRetries = maxRetries
	}
}

func WithLogger(logger *log.Logger) func(*LeakZeroClient) {
	return func(c *LeakZeroClient) {
		c.Logger = logger
	}
}

func (c *LeakZeroClient) generateHeaders() map[string]string {
	return map[string]string{
		"x-api-key":     c.APIKey,
		"x-timestamp":   time.Now().UTC().Format(time.RFC3339),
		"x-request-id":  c.generateRequestID(),
		"Content-Type":  "application/json",
		"User-Agent":    "LeakZero-Go-SDK/1.0.0",
	}
}

func (c *LeakZeroClient) generateRequestID() string {
	return fmt.Sprintf("req_%d_%s", time.Now().Unix(), uuid.New().String()[:8])
}

func (c *LeakZeroClient) makeRequest(ctx context.Context, method, endpoint string, payload interface{}) (*http.Response, error) {
	var body io.Reader

	if payload != nil {
		jsonData, err := json.Marshal(payload)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal payload: %w", err)
		}
		body = bytes.NewBuffer(jsonData)
	}

	url := c.BaseURL + endpoint

	for attempt := 0; attempt <= c.MaxRetries; attempt++ {
		req, err := http.NewRequestWithContext(ctx, method, url, body)
		if err != nil {
			return nil, fmt.Errorf("failed to create request: %w", err)
		}

		for key, value := range c.generateHeaders() {
			req.Header.Set(key, value)
		}

		resp, err := c.HTTPClient.Do(req)
		if err != nil {
			if attempt == c.MaxRetries {
				return nil, fmt.Errorf("request failed after %d attempts: %w", c.MaxRetries+1, err)
			}
			c.Logger.Printf("Request attempt %d failed: %v", attempt+1, err)
			time.Sleep(time.Duration(attempt+1) * time.Second)
			continue
		}

		if resp.StatusCode == 429 {
			retryAfterStr := resp.Header.Get("Retry-After")
			retryAfter := 5 // default
			if retryAfterStr != "" {
				if parsed, err := strconv.Atoi(retryAfterStr); err == nil {
					retryAfter = parsed
				}
			}

			if retryAfter > 30 {
				retryAfter = 30
			}

			c.Logger.Printf("Rate limited. Waiting %ds", retryAfter)
			resp.Body.Close()

			select {
			case <-time.After(time.Duration(retryAfter) * time.Second):
				continue
			case <-ctx.Done():
				return nil, ctx.Err()
			}
		}

		if resp.StatusCode >= 400 {
			defer resp.Body.Close()

			var apiError APIError
			if err := json.NewDecoder(resp.Body).Decode(&apiError); err != nil {
				return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, resp.Status)
			}
			apiError.StatusCode = resp.StatusCode
			return nil, &apiError
		}

		c.Logger.Printf("API Request successful: %s %s", method, endpoint)
		return resp, nil
	}

	return nil, fmt.Errorf("max retries exceeded")
}

func (c *LeakZeroClient) GetBalance(ctx context.Context) (*BalanceResponse, error) {
	resp, err := c.makeRequest(ctx, "GET", "/public/balance", nil)
	if err != nil {
		c.Logger.Printf("Failed to get balance: %v", err)
		return nil, err
	}
	defer resp.Body.Close()

	var balance BalanceResponse
	if err := json.NewDecoder(resp.Body).Decode(&balance); err != nil {
		return nil, fmt.Errorf("failed to decode balance response: %w", err)
	}

	return &balance, nil
}

func (c *LeakZeroClient) RegularSearch(ctx context.Context, options SearchOptions) (*SearchResult, error) {
	if options.Option == "" {
		options.Option = "exact"
	}
	if options.RowLimit == 0 {
		options.RowLimit = 1000
	}
	if options.RowLimit > 10000 {
		options.RowLimit = 10000
	}

	c.Logger.Printf("Searching for %s: %s", options.Field, options.Value)

	resp, err := c.makeRequest(ctx, "POST", "/public/search/regular", options)
	if err != nil {
		c.Logger.Printf("Regular search failed: %v", err)
		return nil, err
	}
	defer resp.Body.Close()

	var data map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return nil, fmt.Errorf("failed to decode search response: %w", err)
	}

	totalResults := 0
	if val := resp.Header.Get("x-rows-returned"); val != "" {
		totalResults, _ = strconv.Atoi(val)
	}

	cost := 0.0
	if val := resp.Header.Get("x-charge"); val != "" {
		if charge, err := strconv.Atoi(val); err == nil {
			cost = float64(charge) / 1_000_000_000
		}
	}

	processingTime := 0
	if val := resp.Header.Get("x-processing-time"); val != "" {
		processingTime, _ = strconv.Atoi(val)
	}

	result := &SearchResult{
		Data:           []map[string]interface{}{},
		TotalResults:   totalResults,
		Cost:           cost,
		RequestID:      resp.Header.Get("x-request-id"),
		ProcessingTime: processingTime,
	}

	if dataArray, ok := data["data"].([]interface{}); ok {
		for _, item := range dataArray {
			if record, ok := item.(map[string]interface{}); ok {
				result.Data = append(result.Data, record)
			}
		}
	}

	c.Logger.Printf("Found %d records (Cost: $%.6f)", result.TotalResults, result.Cost)
	return result, nil
}

func (c *LeakZeroClient) AdvancedSearch(ctx context.Context, queries []SearchOptions, rowLimit int) (*SearchResult, error) {
	if len(queries) == 0 {
		return nil, fmt.Errorf("at least one query is required")
	}

	if rowLimit == 0 {
		rowLimit = 1000
	}
	if rowLimit > 10000 {
		rowLimit = 10000
	}

	payload := map[string]interface{}{
		"queries":  queries,
		"rowLimit": rowLimit,
	}

	c.Logger.Printf("Advanced search with %d queries", len(queries))

	resp, err := c.makeRequest(ctx, "POST", "/public/search/advanced", payload)
	if err != nil {
		c.Logger.Printf("Advanced search failed: %v", err)
		return nil, err
	}
	defer resp.Body.Close()

	var data map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return nil, fmt.Errorf("failed to decode advanced search response: %w", err)
	}

	// Parse response similar to RegularSearch
	result := &SearchResult{
		Data: []map[string]interface{}{},
	}

	if dataArray, ok := data["data"].([]interface{}); ok {
		for _, item := range dataArray {
			if record, ok := item.(map[string]interface{}); ok {
				result.Data = append(result.Data, record)
			}
		}
	}

	c.Logger.Printf("Advanced search completed")
	return result, nil
}

func (c *LeakZeroClient) IdentityLinkingSearch(ctx context.Context, field, value, contextDomain string, maxResults int, includePossible bool) (*SearchResult, error) {
	if maxResults == 0 {
		maxResults = 50
	}
	if maxResults > 100 {
		maxResults = 100
	}

	payload := map[string]interface{}{
		"field":           field,
		"value":           value,
		"maxDepth":        2,
		"minConfidence":   0.35,
		"maxResults":      maxResults,
		"includePossible": includePossible,
	}
	if contextDomain != "" {
		payload["contextDomain"] = contextDomain
	}

	c.Logger.Printf("identity linking search for: %s:%s", field, value)

	resp, err := c.makeRequest(ctx, "POST", "/public/search/identity-linking", payload)
	if err != nil {
		c.Logger.Printf("Identity linking search failed: %v", err)
		return nil, err
	}
	defer resp.Body.Close()

	var data map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return nil, fmt.Errorf("failed to decode identity linking response: %w", err)
	}

	result := &SearchResult{
		Data:     []map[string]interface{}{},
		Analysis: make(map[string]interface{}),
	}

	if correlation, ok := data["data"].(map[string]interface{}); ok {
		result.Analysis["summary"] = correlation["summary"]
		result.Analysis["metadata"] = correlation["metadata"]
		if candidates, ok := correlation["results"].([]interface{}); ok {
			for _, item := range candidates {
				if candidate, ok := item.(map[string]interface{}); ok {
					result.Data = append(result.Data, candidate)
				}
			}
		}
	}

	c.Logger.Printf("Identity linking completed")
	return result, nil
}

func (c *LeakZeroClient) GetUsageStats(ctx context.Context) (*UsageStats, error) {
	resp, err := c.makeRequest(ctx, "GET", "/public/usage/stats", nil)
	if err != nil {
		c.Logger.Printf("Failed to get usage stats: %v", err)
		return nil, err
	}
	defer resp.Body.Close()

	var stats UsageStats
	if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
		return nil, fmt.Errorf("failed to decode usage stats: %w", err)
	}

	return &stats, nil
}

func (c *LeakZeroClient) BulkSearch(ctx context.Context, searchTerms []string, field string, batchSize int, delay time.Duration) ([]map[string]interface{}, error) {
	if batchSize == 0 {
		batchSize = 5
	}
	if delay == 0 {
		delay = 200 * time.Millisecond
	}

	var results []map[string]interface{}
	var mu sync.Mutex
	var wg sync.WaitGroup

	c.Logger.Printf("Starting bulk search for %d terms", len(searchTerms))

	for i := 0; i < len(searchTerms); i += batchSize {
		end := i + batchSize
		if end > len(searchTerms) {
			end = len(searchTerms)
		}
		batch := searchTerms[i:end]

		for j, term := range batch {
			wg.Add(1)
			go func(term string, index int) {
				defer wg.Done()

				if index > 0 {
					time.Sleep(delay)
				}

				result, err := c.RegularSearch(ctx, SearchOptions{
					Field:    field,
					Value:    term,
					RowLimit: 100,
				})

				resultData := map[string]interface{}{
					"term":    term,
					"success": err == nil,
				}

				if err != nil {
					resultData["error"] = err.Error()
					c.Logger.Printf("Failed to search for %s: %v", term, err)
				} else {
					resultData["result"] = result
				}

				mu.Lock()
				results = append(results, resultData)
				mu.Unlock()
			}(term, j)
		}

		wg.Wait()

		processed := min(i+batchSize, len(searchTerms))
		c.Logger.Printf("Processed %d/%d terms", processed, len(searchTerms))

		if i+batchSize < len(searchTerms) {
			time.Sleep(delay * 2)
		}
	}

	successful := 0
	for _, result := range results {
		if result["success"].(bool) {
			successful++
		}
	}

	c.Logger.Printf("Bulk search completed: %d successful, %d failed", successful, len(results)-successful)
	return results, nil
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func demonstrateBasicUsage() {
	apiKey := os.Getenv("LEAKZERO_API_KEY")
	if apiKey == "" {
		log.Fatal("LEAKZERO_API_KEY environment variable is required")
	}

	client := NewLeakZeroClient(apiKey, WithMaxRetries(5))
	ctx := context.Background()

	fmt.Println("Checking API balance...")
	balance, err := client.GetBalance(ctx)
	if err != nil {
		log.Printf("Error getting balance: %v", err)
		return
	}
	fmt.Printf("Current balance: $%.6f
", balance.Balance)

	if balance.Balance < 0.001 {
		log.Fatal("Insufficient balance. Please top up your account.")
	}

	fmt.Println("
Performing regular search...")
	result, err := client.RegularSearch(ctx, SearchOptions{
		Field:    "email",
		Value:    "[email protected]",
		Option:   "exact",
		RowLimit: 100,
	})
	if err != nil {
		log.Printf("Search error: %v", err)
		return
	}

	fmt.Printf("Found %d records
", result.TotalResults)
	fmt.Printf("Cost: $%.6f
", result.Cost)

	for i, record := range result.Data {
		if i >= 5 { // Show first 5
			break
		}
		breachName := "Unknown"
		breachDate := "Unknown"

		if val, ok := record["breach_name"].(string); ok {
			breachName = val
		}
		if val, ok := record["breach_date"].(string); ok {
			breachDate = val
		}

		fmt.Printf("Breach: %s, Date: %s
", breachName, breachDate)
	}

	fmt.Println("
Getting usage statistics...")
	stats, err := client.GetUsageStats(ctx)
	if err != nil {
		log.Printf("Stats error: %v", err)
		return
	}
	fmt.Printf("Total requests: %d
", stats.TotalRequests)
	fmt.Printf("Total cost: $%.6f
", stats.TotalCost)
}

func demonstrateConcurrentUsage() {
	apiKey := os.Getenv("LEAKZERO_API_KEY")
	if apiKey == "" {
		log.Fatal("LEAKZERO_API_KEY environment variable is required")
	}

	client := NewLeakZeroClient(apiKey)
	ctx := context.Background()

	searchTerms := []string{"[email protected]", "[email protected]", "[email protected]"}

	var wg sync.WaitGroup
	results := make([]*SearchResult, len(searchTerms))

	for i, term := range searchTerms {
		wg.Add(1)
		go func(index int, searchTerm string) {
			defer wg.Done()

			result, err := client.RegularSearch(ctx, SearchOptions{
				Field:    "email",
				Value:    searchTerm,
				RowLimit: 50,
			})

			if err != nil {
				log.Printf("Search failed for %s: %v", searchTerm, err)
				return
			}

			results[index] = result
		}(i, term)
	}

	wg.Wait()

	successful := 0
	for _, result := range results {
		if result != nil {
			successful++
		}
	}

	fmt.Printf("Completed %d concurrent searches
", successful)
}

func main() {
	demonstrateBasicUsage()

	fmt.Println("
" + strings.Repeat("=", 50))
	demonstrateConcurrentUsage()
}
Type Safety: Strong typing with structs and interfaces for better compile-time checks
Concurrency: Goroutines and channels for efficient parallel processing
Context Support: Proper context handling for timeouts and cancellation
Key Features

Core Features

  • • Strong type safety with structs and interfaces
  • • Context-aware requests with timeout support
  • • Automatic retry with exponential backoff
  • • Rate limit handling with intelligent delays
  • • Comprehensive error handling and logging

Performance Features

  • • Goroutine-based concurrent operations
  • • Connection pooling and HTTP keep-alive
  • • Bulk search operations with batching
  • • Memory-efficient JSON streaming
  • • Configurable timeout and retry settings
Best Practices:
  • • Always use environment variables for API keys
  • • Implement proper context handling for production use
  • • Use goroutines for concurrent searches to improve performance
  • • Monitor your API usage and balance regularly
  • • Use structured logging for better debugging
Documentation - LeakZero | LeakZero