Setting the file. One moment.
Subchapter 22.3
references/go-setup.mdMarkdown12 KBView on GitHub
Implementation patterns for Go applications using the LaunchDarkly API.
go get github.com/joho/godotenvCreate a package for project operations:
// pkg/launchdarkly/projects.go
package launchdarkly
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
const BaseURL = "https://app.launchdarkly.com/api/v2"
type ProjectManager struct {
apiToken string
client
package main
import (
"fmt"
"log"
"yourmodule/pkg/launchdarkly"
)
func main() {
pm := launchdarkly.NewProjectManager("")
project, err := pm.CreateProject(
"Customer Agent Service",
"customer-ai",
[]string{"ai-configs", "production"},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("✓ Created project: %s (%s)\n", project.Name, project.Key)
}func main() {
pm := launchdarkly.NewProjectManager("")
// Get production SDK key
sdkKey, err := pm.GetSDKKey("customer-ai", "production")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Production SDK Key: %s\n", sdkKey)
}func main() {
pm := launchdarkly.NewProjectManager("")
projects, err := pm.ListProjects()
if err != nil {
log.Fatal(err)
}
fmt.Println("Projects:")
for _, project := range projects {
fmt.Printf(" - %s (%s)\n", project.Name, project.Key)
}
}Integrate into an HTTP server:
// cmd/server/main.go
package main
import (
"log"
"net/http"
"os"
"yourmodule/pkg/launchdarkly"
)
func main() {
// Initialize LaunchDarkly project
pm := launchdarkly.NewProjectManager(os.Getenv("LAUNCHDARKLY_API_TOKEN"))
project, err := pm.CreateProject(
"Go API Service",
"go-api-service",
[]string{"api", "ai-configs"},
)
if err != nil {
log.Fatalf("Failed to initialize LaunchDarkly: %v", err)
}
// Get SDK key
sdkKey, err := pm.GetSDKKey("go-api-service", "production")
if err != nil {
log.Fatalf("Failed to get SDK key: %v", err)
}
// Store SDK key for SDK initialization
os.Setenv("LAUNCHDARKLY_SDK_KEY", sdkKey)
log.Printf("✓ LaunchDarkly project ready: %s\n", project.Key)
// Start server
http.HandleFunc("/health", healthHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}Create a CLI for project management:
// cmd/ldprojects/main.go
package main
import (
"flag"
"fmt"
"log"
"os"
"strings"
"yourmodule/pkg/launchdarkly"
)
func main() {
createCmd := flag.NewFlagSet("create", flag.ExitOnError)
createName := createCmd.String("name", "", "Project name")
createKey := createCmd.String("key", "", "Project key")
createTags := createCmd.String("tags", "", "Comma-separated tags")
listCmd := flag.NewFlagSet("list", flag.ExitOnError)
getKeyCmd := flag.NewFlagSet("get-key", flag.ExitOnError)
getKeyProject := getKeyCmd.String("project", "", "Project key")
getKeyEnv := getKeyCmd.String("env", "production", "Environment")
if len(os.Args) < 2 {
fmt.Println("Usage: ldprojects [create|list|get-key] [options]")
os.Exit(1)
}
pm := launchdarkly.NewProjectManager("")
switch os.Args[1] {
case "create":
createCmd.Parse(os.Args[2:])
if *createName == "" || *createKey == "" {
log.Fatal("name and key are required")
}
var tags []string
if *createTags != "" {
tags = strings.Split(*createTags, ",")
}
project, err := pm.CreateProject(*createName, *createKey, tags)
if err != nil {
log.Fatal(err)
}
fmt.Printf("✓ Created: %s (%s)\n", project.Name, project.Key)
case "list":
listCmd.Parse(os.Args[2:])
projects, err := pm.ListProjects()
if err != nil {
log.Fatal(err)
}
fmt.Println("Projects:")
for _, project := range projects {
fmt.Printf(" - %s (%s)\n", project.Name, project.Key)
}
case "get-key":
getKeyCmd.Parse(os.Args[2:])
if *getKeyProject == "" {
log.Fatal("project is required")
}
sdkKey, err := pm.GetSDKKey(*getKeyProject, *getKeyEnv)
if err != nil {
log.Fatal(err)
}
fmt.Println(sdkKey)
default:
fmt.Println("Unknown command:", os.Args[1])
os.Exit(1)
}
}Usage:
go run cmd/ldprojects/main.go create -name "My Agent" -key my-ai -tags ai-configs,production
go run cmd/ldprojects/main.go list
go run cmd/ldprojects/main.go get-key -project my-ai -env productionAdd comprehensive error handling:
type LaunchDarklyError struct {
StatusCode int
Message string
}
func (e *LaunchDarklyError) Error() string {
return fmt.Sprintf("LaunchDarkly API error (%d): %s", e.StatusCode, e.Message)
}
func (pm *ProjectManager) CreateProject(name, key string, tags []string) (*Project, error) {
// ... request setup ...
resp, err := pm.client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusCreated:
var project Project
if err := json.NewDecoder(resp.Body).Decode(&project); err != nil {
return nil, fmt.Errorf("decode response: %w", err)
}
return &project, nil
case http.StatusConflict:
return pm.GetProject(key)
case http.StatusUnauthorized:
return nil, &LaunchDarklyError{resp.StatusCode, "Invalid API token"}
case http.StatusForbidden:
return nil, &LaunchDarklyError{resp.StatusCode, "Insufficient permissions (need projects:write)"}
default:
body, _ := io.ReadAll(resp.Body)
return nil, &LaunchDarklyError{resp.StatusCode, string(body)}
}
}Mock the HTTP client for testing:
// pkg/launchdarkly/projects_test.go
package launchdarkly
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestCreateProject(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
t.Errorf("Expected POST, got %s", r.Method)
}
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"name":"Test","key":"test","tags":[]}`))
}))
defer server.Close()
pm := &ProjectManager{
apiToken: "test-token",
client: server.Client(),
}
// Override BaseURL for test
oldBaseURL := BaseURL
BaseURL = server.URL
defer func() { BaseURL = oldBaseURL }()
project, err := pm.CreateProject("Test", "test", nil)
if err != nil {
t.Fatalf("CreateProject failed: %v", err)
}
if project.Key != "test" {
t.Errorf("Expected key 'test', got '%s'", project.Key)
}
}