Go Client SDK
Official Go client library for Providence API
The Providence Go SDK provides a type-safe, idiomatic Go interface for interacting with the Providence API.
Installation
Install the SDK using go get:
go get github.com/providence-ai/providence-goQuick Start
package main
import (
"context"
"fmt"
"log"
"github.com/providence-ai/providence-go"
)
func main() {
// Create a new client
client := providence.NewClient(
providence.WithAPIKey("pvd_live_your_api_key"),
providence.WithBaseURL("https://api.providence.io"), // Optional
)
// List projects
projects, err := client.Projects.List(context.Background(), &providence.ListProjectsParams{
Limit: providence.Int(10),
})
if err != nil {
log.Fatal(err)
}
for _, project := range projects.Projects {
fmt.Printf("Project: %s (%s)\n", project.Name, project.ID)
}
// Execute a natural language query
result, err := client.Queries.Execute(context.Background(), "proj_123", &providence.ExecuteQueryRequest{
Query: "What were the top 10 products by revenue last month?",
Type: providence.QueryTypeNaturalLanguage,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Query returned %d rows\n", result.Results.RowCount)
}Authentication
API Key Authentication
client := providence.NewClient(
providence.WithAPIKey("pvd_live_your_api_key"),
)JWT Token Authentication
client := providence.NewClient(
providence.WithToken("your_jwt_token"),
)Custom HTTP Client
httpClient := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
},
}
client := providence.NewClient(
providence.WithHTTPClient(httpClient),
providence.WithAPIKey("pvd_live_your_api_key"),
)Core Resources
Projects
// List projects
projects, err := client.Projects.List(ctx, &providence.ListProjectsParams{
OrganizationID: providence.String("org_123"),
Limit: providence.Int(20),
Page: providence.Int(1),
})
// Create a project
project, err := client.Projects.Create(ctx, &providence.CreateProjectRequest{
Name: "Q1 Analytics",
Slug: "q1-analytics",
Description: "First quarter business analytics",
OrganizationID: "org_123",
})
// Get a project
project, err := client.Projects.Get(ctx, "proj_123")
// Update a project
project, err := client.Projects.Update(ctx, "proj_123", &providence.UpdateProjectRequest{
Name: providence.String("Q1 Analytics Updated"),
Description: providence.String("Updated description"),
})
// Delete a project
err := client.Projects.Delete(ctx, "proj_123", &providence.DeleteProjectRequest{
Confirmation: "DELETE_PROJECT_Q1_ANALYTICS",
})Datasets
// List datasets in a project
datasets, err := client.Datasets.List(ctx, "proj_123", &providence.ListDatasetsParams{
Type: providence.String("file"),
Search: providence.String("sales"),
})
// Upload a file for dataset
file, err := os.Open("sales_data.csv")
defer file.Close()
uploadResult, err := client.Datasets.Upload(ctx, "proj_123", &providence.UploadDatasetRequest{
File: file,
Name: "Sales Data 2024",
Description: "Annual sales data",
})
// Create dataset from upload
dataset, err := client.Datasets.Create(ctx, "proj_123", &providence.CreateDatasetRequest{
Name: "Sales Data 2024",
Description: "Annual sales data",
Type: "file",
Source: &providence.DatasetSource{
Type: "csv",
FileID: uploadResult.FileID,
},
})
// Get dataset details
dataset, err := client.Datasets.Get(ctx, "proj_123", "ds_456")
// Preview dataset
preview, err := client.Datasets.Preview(ctx, "proj_123", "ds_456", &providence.PreviewDatasetParams{
Limit: providence.Int(100),
})
// Delete dataset
err := client.Datasets.Delete(ctx, "proj_123", "ds_456")Queries
// Execute a query
result, err := client.Queries.Execute(ctx, "proj_123", &providence.ExecuteQueryRequest{
Query: "Show me total sales by region",
Type: providence.QueryTypeNaturalLanguage,
Options: &providence.QueryOptions{
Limit: providence.Int(1000),
TimeoutSeconds: providence.Int(30),
Explain: providence.Bool(true),
Cache: providence.Bool(true),
},
})
// Handle results
for _, row := range result.Results.Rows {
// Process each row
region := row[0].(string)
sales := row[1].(float64)
fmt.Printf("Region: %s, Sales: $%.2f\n", region, sales)
}
// Stream query execution
stream, err := client.Queries.Stream(ctx, "proj_123", &providence.ExecuteQueryRequest{
Query: "SELECT * FROM large_dataset",
Type: providence.QueryTypeSQL,
})
// Process streaming results
for event := range stream.Events() {
switch e := event.(type) {
case *providence.QueryStatusEvent:
fmt.Printf("Status: %s\n", e.Message)
case *providence.QuerySchemaEvent:
fmt.Printf("Columns: %v\n", e.Columns)
case *providence.QueryRowEvent:
fmt.Printf("Row: %v\n", e.Values)
case *providence.QueryCompleteEvent:
fmt.Printf("Completed: %d rows in %dms\n", e.RowCount, e.ExecutionTimeMs)
case *providence.QueryErrorEvent:
log.Printf("Error: %s\n", e.Error)
}
}
// Get query history
history, err := client.Queries.List(ctx, "proj_123", &providence.ListQueriesParams{
Type: providence.String("natural_language"),
Status: providence.String("completed"),
Limit: providence.Int(50),
})
// Save a query
saved, err := client.Queries.Save(ctx, "proj_123", "qry_789", &providence.SaveQueryRequest{
Name: "Monthly Sales Report",
Description: "Top customers by monthly sales",
Tags: []string{"sales", "monthly", "customers"},
})Organizations
// List organizations
orgs, err := client.Organizations.List(ctx, &providence.ListOrganizationsParams{
Role: providence.String("admin"),
})
// Get organization details
org, err := client.Organizations.Get(ctx, "org_123")
// Update organization
org, err := client.Organizations.Update(ctx, "org_123", &providence.UpdateOrganizationRequest{
Name: providence.String("Acme Corp International"),
Description: providence.String("Global leader in innovation"),
})
// Manage teams
team, err := client.Organizations.CreateTeam(ctx, "org_123", &providence.CreateTeamRequest{
Name: "Data Science",
Slug: "data-science",
Description: "Data science and ML team",
})
// Invite users
invite, err := client.Organizations.InviteUser(ctx, "org_123", &providence.InviteUserRequest{
Email: "[email protected]",
Role: "member",
Teams: []string{"team_123"},
Message: "Welcome to our team!",
})Advanced Features
Error Handling
result, err := client.Queries.Execute(ctx, "proj_123", &providence.ExecuteQueryRequest{
Query: "invalid query",
})
if err != nil {
// Check for specific error types
if apiErr, ok := err.(*providence.APIError); ok {
fmt.Printf("API Error: %s (Code: %s)\n", apiErr.Message, apiErr.Code)
// Handle specific error codes
switch apiErr.Code {
case "INVALID_QUERY":
// Handle invalid query
case "QUERY_TIMEOUT":
// Handle timeout
case "RATE_LIMIT_EXCEEDED":
// Handle rate limit
retryAfter := apiErr.Details["retry_after"].(int)
time.Sleep(time.Duration(retryAfter) * time.Second)
}
}
}Pagination
// Helper function for paginating through all results
func getAllProjects(client *providence.Client, orgID string) ([]*providence.Project, error) {
var allProjects []*providence.Project
page := 1
for {
projects, err := client.Projects.List(context.Background(), &providence.ListProjectsParams{
OrganizationID: providence.String(orgID),
Page: providence.Int(page),
Limit: providence.Int(100),
})
if err != nil {
return nil, err
}
allProjects = append(allProjects, projects.Projects...)
if page >= projects.Pagination.Pages {
break
}
page++
}
return allProjects, nil
}Retry Logic
// Configure client with retry
client := providence.NewClient(
providence.WithAPIKey("pvd_live_your_api_key"),
providence.WithRetry(providence.RetryConfig{
MaxAttempts: 3,
InitialDelay: 1 * time.Second,
MaxDelay: 10 * time.Second,
Multiplier: 2,
}),
)Context and Cancellation
// Use context for timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result, err := client.Queries.Execute(ctx, "proj_123", &providence.ExecuteQueryRequest{
Query: "Complex analytical query",
})
// Check if context was cancelled
if err != nil && errors.Is(err, context.Canceled) {
fmt.Println("Query was cancelled")
}Concurrent Operations
// Execute multiple queries concurrently
queries := []string{
"Total sales by region",
"Top customers by revenue",
"Product performance metrics",
}
type queryResult struct {
Query string
Result *providence.QueryResult
Error error
}
resultsChan := make(chan queryResult, len(queries))
var wg sync.WaitGroup
for _, query := range queries {
wg.Add(1)
go func(q string) {
defer wg.Done()
result, err := client.Queries.Execute(context.Background(), "proj_123",
&providence.ExecuteQueryRequest{
Query: q,
Type: providence.QueryTypeNaturalLanguage,
},
)
resultsChan <- queryResult{Query: q, Result: result, Error: err}
}(query)
}
go func() {
wg.Wait()
close(resultsChan)
}()
// Collect results
for res := range resultsChan {
if res.Error != nil {
log.Printf("Error executing '%s': %v\n", res.Query, res.Error)
} else {
fmt.Printf("Query '%s' returned %d rows\n", res.Query, res.Result.Results.RowCount)
}
}Custom Request Options
// Add custom headers or modify requests
client := providence.NewClient(
providence.WithAPIKey("pvd_live_your_api_key"),
providence.WithRequestHook(func(req *http.Request) error {
// Add custom header
req.Header.Set("X-Request-ID", uuid.New().String())
// Add tracing
fmt.Printf("[%s] %s %s\n", time.Now().Format(time.RFC3339), req.Method, req.URL)
return nil
}),
)Type Definitions
The SDK provides comprehensive type definitions for all API resources:
// Project represents a Providence project
type Project struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
OrganizationID string `json:"organization_id"`
Organization *Organization `json:"organization,omitempty"`
Visibility string `json:"visibility"`
Status string `json:"status"`
Settings *ProjectSettings `json:"settings,omitempty"`
Statistics *ProjectStats `json:"statistics,omitempty"`
Tags []string `json:"tags,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CreatedBy *User `json:"created_by,omitempty"`
}
// QueryResult represents the result of a query execution
type QueryResult struct {
QueryID string `json:"query_id"`
Status string `json:"status"`
Type string `json:"type"`
OriginalQuery string `json:"original_query"`
GeneratedSQL string `json:"generated_sql,omitempty"`
Results *ResultSet `json:"results"`
Explanation *QueryExplanation `json:"explanation,omitempty"`
Metadata *QueryMetadata `json:"metadata"`
CreatedAt time.Time `json:"created_at"`
}Testing
Mock Client
// Use the mock client for testing
mockClient := providence.NewMockClient()
// Configure mock responses
mockClient.Projects.OnList().Return(&providence.ListProjectsResponse{
Projects: []*providence.Project{
{
ID: "proj_test",
Name: "Test Project",
},
},
}, nil)
// Use in tests
projects, err := mockClient.Projects.List(context.Background(), nil)
assert.NoError(t, err)
assert.Len(t, projects.Projects, 1)Integration Testing
// Create a test client with sandbox environment
testClient := providence.NewClient(
providence.WithAPIKey(os.Getenv("PROVIDENCE_TEST_API_KEY")),
providence.WithBaseURL("https://sandbox.api.providence.io"),
)
// Run integration tests
t.Run("CreateAndQueryDataset", func(t *testing.T) {
// Create test project
project, err := testClient.Projects.Create(context.Background(),
&providence.CreateProjectRequest{
Name: fmt.Sprintf("Test Project %d", time.Now().Unix()),
OrganizationID: "org_test",
},
)
require.NoError(t, err)
defer testClient.Projects.Delete(context.Background(), project.ID, nil)
// Upload dataset
// ... test dataset operations
})Best Practices
- Error Handling: Always check and handle errors appropriately
- Context Usage: Use context for cancellation and timeouts
- Resource Cleanup: Use defer for cleaning up resources
- Pagination: Handle pagination for large result sets
- Rate Limiting: Implement backoff for rate limit errors
- Logging: Add structured logging for debugging
Migration Guide
From v1 to v2
// v1
client := providence.New("api_key")
projects, err := client.ListProjects()
// v2
client := providence.NewClient(
providence.WithAPIKey("api_key"),
)
projects, err := client.Projects.List(ctx, nil)Support
- Documentation: https://docs.providence.io
- API Reference: https://api.providence.io/docs
- Issues: https://github.com/providence-ai/providence-go/issues
- Examples: https://github.com/providence-ai/providence-go/tree/main/examples