Skip to main content

Go SDK

The Collate Go SDK provides a type-safe, auto-generated client library for Go applications to interact with the Collate API. Built from OpenAPI specifications, it offers strongly typed services for 60+ entity types with automatic pagination, retry logic, and comprehensive error handling. You can find the source code in the GitHub repository. As an open-source project, contributions are always welcome!

Requirements

  • Go 1.24 or higher

Installation

go get github.com/open-metadata/openmetadata-sdk/openmetadata-go-client@latest

Quick Start

Basic Connection

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/open-metadata/openmetadata-sdk/openmetadata-go-client/pkg/ometa"
)

func main() {
    client := ometa.NewClient(
        "http://localhost:8585",
        ometa.WithToken("your-jwt-token"),
    )

    ctx := context.Background()

    // List all tables
    for table, err := range client.Tables.List(ctx, nil) {
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(table.Name)
    }
}

Client Configuration Options

OptionDescriptionDefault
WithToken(token)JWT Bearer token for authentication""
WithAPIVersion(v)Override API version"v1"
WithRetry(count, wait)Retry attempts and wait duration3 retries, 30s wait
WithHTTPClient(c)Custom *http.ClientDefault client
client := ometa.NewClient(
    "http://localhost:8585",
    ometa.WithToken("your-jwt-token"),
    ometa.WithRetry(5, 10*time.Second),
    ometa.WithAPIVersion("v1"),
)
Retryable status codes are 429 (Too Many Requests) and 504 (Gateway Timeout).

Core Functionality

Available Services

The client exposes typed services for all entity types. Here are the most commonly used: Data Assets: Tables, Topics, Dashboards, Pipelines, Charts, Containers, SearchIndexes, StoredProcedures, Queries Data Organization: Databases, DatabaseSchemas, APICollections, APIEndpoints Governance: Glossaries, GlossaryTerms, Classifications, Tags, DataProducts, Domains, Policies Quality: TestCases, TestSuites, TestDefinitions Services: DatabaseServices, DashboardServices, PipelineServices, MessagingServices, SearchServices, StorageServices People & Access: Users, Teams, Roles, Bots Other: IngestionPipelines, EventSubscriptions, MlModels

Standard Operations

All services follow the same consistent pattern with these methods:

List

Returns a Go iterator (iter.Seq2) that handles pagination automatically.
for table, err := range client.Tables.List(ctx, &ometa.ListTablesParams{
    Limit:  ometa.Int32(100),
    Fields: ometa.Str("*"),
}) {
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(table.Name)
}

GetByID

Retrieve an entity by UUID.
table, err := client.Tables.GetByID(ctx, "uuid-here", &ometa.GetTableByIDParams{
    Fields: ometa.Str("*"),
})

GetByName

Retrieve an entity by fully qualified name (FQN).
table, err := client.Tables.GetByName(ctx, "service.database.schema.table", nil)

Create

Create a new entity.
table, err := client.Tables.Create(ctx, &ometa.CreateTable{
    Name:           "customers",
    DatabaseSchema: "production.analytics_db.public",
    Columns: []ometa.Column{
        {Name: "id", DataType: "INT"},
        {Name: "email", DataType: "STRING"},
    },
    Description: ometa.Str("Customer master data"),
})

CreateOrUpdate

Upsert an entity - creates if it doesn’t exist, updates if it does.
table, err := client.Tables.CreateOrUpdate(ctx, &ometa.CreateTable{
    Name:           "customers",
    DatabaseSchema: "production.analytics_db.public",
    Columns: []ometa.Column{
        {Name: "id", DataType: "INT"},
        {Name: "email", DataType: "STRING"},
    },
    Description: ometa.Str("Updated description"),
})

Patch

Apply JSON Patch operations (RFC 6902) to update specific fields.
table, err := client.Tables.Patch(ctx, "uuid-here", []ometa.JSONPatchOp{
    {Op: "add", Path: "/description", Value: "New description"},
    {Op: "replace", Path: "/displayName", Value: "Customer Records"},
})

Delete / DeleteByName

Delete an entity by ID or fully qualified name. Supports soft and hard deletes.
// Soft delete by ID
err := client.Tables.Delete(ctx, "uuid-here", &ometa.DeleteTableParams{
    HardDelete: ometa.Bool(false),
})

// Hard delete by name
err := client.Tables.DeleteByName(ctx, "service.database.schema.table", &ometa.DeleteTable1Params{
    HardDelete: ometa.Bool(true),
})

Restore

Restore a soft-deleted entity.
table, err := client.Tables.Restore(ctx, &ometa.RestoreEntity{
    Id: entityUUID,
})

ListVersions / GetVersion

Access entity version history.
// Get all versions
history, err := client.Tables.ListVersions(ctx, "uuid-here")

// Get specific version
table, err := client.Tables.GetVersion(ctx, "uuid-here", "0.2")

Pointer Helpers

Since many fields are optional (pointers), the SDK provides helper functions:
ometa.Str("value")     // returns *string
ometa.Bool(true)       // returns *bool
ometa.Int32(100)       // returns *int32
ometa.Int64(100)       // returns *int64
ometa.Float32(1.0)     // returns *float32
ometa.Float64(1.0)     // returns *float64
ometa.Ptr(value)       // returns *T (generic, works with any type)

Error Handling

table, err := client.Tables.GetByID(ctx, "some-id", nil)

if ometa.IsNotFound(err) {
    fmt.Println("Table not found")
} else if ometa.IsConflict(err) {
    fmt.Println("Conflict detected")
} else if err != nil {
    if apiErr, ok := err.(*ometa.APIError); ok {
        fmt.Printf("API Error: %d - %s\n", apiErr.StatusCode, apiErr.Message)
    }
    log.Fatal(err)
}
The APIError type provides:
  • StatusCode - HTTP status code
  • Code - API error code
  • Message - Error message

Common Use Cases

Create a Database Service, Database, Schema, and Table

ctx := context.Background()

// Create database service
svc, err := client.DatabaseServices.Create(ctx, &ometa.CreateDatabaseService{
    Name:        "postgres-prod",
    ServiceType: "Postgres",
})

// Create database
db, err := client.Databases.Create(ctx, &ometa.CreateDatabase{
    Name:    "analytics",
    Service: "postgres-prod",
})

// Create schema
schema, err := client.DatabaseSchemas.Create(ctx, &ometa.CreateDatabaseSchema{
    Name:     "public",
    Database: "postgres-prod.analytics",
})

// Create table
table, err := client.Tables.Create(ctx, &ometa.CreateTable{
    Name:           "events",
    DatabaseSchema: "postgres-prod.analytics.public",
    Columns: []ometa.Column{
        {
            Name:     "event_id",
            DataType: "INT",
        },
        {
            Name:        "event_type",
            DataType:    "STRING",
            Description: ometa.Str("Type of event"),
        },
        {
            Name:     "created_at",
            DataType: "TIMESTAMP",
        },
    },
    Description: ometa.Str("Application event log"),
})

Iterate Over All Tables

ctx := context.Background()
count := 0

for table, err := range client.Tables.List(ctx, &ometa.ListTablesParams{
    Limit:  ometa.Int32(50),
    Fields: ometa.Str("*"),
}) {
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s (FQN: %s)\n", table.Name, *table.FullyQualifiedName)
    count++
}

fmt.Printf("Total: %d tables\n", count)

Update Metadata with Patch

ctx := context.Background()

table, err := client.Tables.Patch(ctx, tableID, []ometa.JSONPatchOp{
    {Op: "add", Path: "/description", Value: "Production customer data"},
    {Op: "add", Path: "/displayName", Value: "Customer Records"},
})

Soft Delete and Restore

ctx := context.Background()

// Soft delete
err := client.Tables.Delete(ctx, tableID, &ometa.DeleteTableParams{
    HardDelete: ometa.Bool(false),
})

// Restore
restored, err := client.Tables.Restore(ctx, &ometa.RestoreEntity{
    Id: tableID,
})

Context with Timeout

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

table, err := client.Tables.GetByName(ctx, "service.db.schema.table", nil)

Best Practices

  1. Use context timeouts: Always set appropriate timeouts for API calls to avoid hanging requests
  2. Handle pagination with iterators: Use range with List methods - the SDK handles cursor-based pagination automatically
  3. Prefer GetByName over GetByID: Fully qualified names are more readable and easier to manage
  4. Use Patch for partial updates: Prefer Patch over CreateOrUpdate when updating specific fields to avoid overwriting other data
  5. Check errors with helpers: Use ometa.IsNotFound() and ometa.IsConflict() for common error handling patterns
  6. Soft delete first: Use soft deletes in production and reserve hard deletes for cleanup operations