Go SDK
Install the gospice Go SDK, then query Spice Cloud or a local Spice runtime over Arrow Flight, with health checks and connection retries.
The Go SDK gospice is the easiest way to query Spice.ai from Go.
It uses Apache Arrow Flight to efficiently stream data to the client and Apache Arrow Records as data frames.
GoDocs are available at pkg.go.dev/github.com/spiceai/gospice/v9.
Requirements
- Go 1.26 or later. gospice v9.1.0 requires Go 1.26. To build with Go 1.25, use gospice v9.0.0.
Installation
Get the gospice package.
go get github.com/spiceai/gospice/v9@latestUsage
1. Import the package.
import gospice "github.com/spiceai/gospice/v9"2. Create a SpiceClient by providing your API key. Get your free API key at spice.ai.
spice := gospice.NewSpiceClient()
defer func() { _ = spice.Close() }()Close() releases the Flight and HTTP connections and must be called.
3. Initialize the SpiceClient.
if err := spice.Init(
gospice.WithApiKey(ApiKey),
gospice.WithSpiceCloudAddress(),
); err != nil {
panic(fmt.Errorf("error initializing SpiceClient: %w", err))
}The options passed to Init are package-level functions on gospice, not methods on the client:
| Option | Description |
|---|---|
WithApiKey(key) | API key. A Spice Cloud key has the form appId|secret. From v9.1.0, any other key that is not empty works with a self-managed runtime that requires an API key. |
WithSpiceCloudAddress() | Connect to Spice Cloud. |
WithFlightAddress(addr) | Arrow Flight address. A grpc:// prefix selects plaintext; otherwise TLS is used. |
WithHttpAddress(addr) | HTTP address, used for health checks and dataset refreshes. |
WithUserAgent(ua) | Prepends to the reported user agent. |
4. Execute a query and get back an Apache Arrow Record Reader.
reader, err := spice.Sql(context.Background(), "SELECT * FROM tpch.lineitem LIMIT 10")
if err != nil {
panic(fmt.Errorf("error querying: %w", err))
}
defer reader.Release()5. Iterate through the reader to access the records.
for reader.Next() {
record := reader.RecordBatch()
defer record.Release()
fmt.Println(record)
}Parameterized queries
SqlWithParams binds positional $1, $2 placeholders:
reader, err := spice.SqlWithParams(
context.Background(),
"SELECT * FROM tpch.lineitem WHERE l_quantity > $1 LIMIT 10",
10,
)From v9.1.0, SqlWithParams also infers the type of these values:
| Value | Binds as |
|---|---|
time.Time | Timestamp(ns, "UTC"), after conversion to UTC. A value outside 1677-09-21 to 2262-04-11 returns an error. |
time.Duration | Duration(ns) |
*T | The value that the pointer points to. A nil *T binds as a NULL of the type of T. |
sql.NullInt64, sql.NullString, sql.NullTime, sql.Null[T] and the other sql.Null* types | The value, or a NULL of that type when Valid is false |
Another driver.Valuer | The value that Value() returns |
A named type, such as type VendorID int64 | Its underlying type |
type VendorID int64
var minFare *float64 // nil: no lower bound
reader, err := spice.SqlWithParams(
context.Background(),
"SELECT * FROM taxi_trips WHERE VendorID = $1 AND ($2 IS NULL OR fare_amount >= $2) LIMIT 10",
VendorID(2), minFare,
)Asynchronous queries
Query and QueryWithParams submit a query for asynchronous execution and return an *AsyncQuery handle instead of a record reader. They require the runtime to be running in distributed (scheduler) mode.
query, err := spice.Query(context.Background(), "SELECT * FROM taxi_trips")
if err != nil {
panic(fmt.Errorf("error submitting query: %w", err))
}
reader, err := query.Results(context.Background()) // waits for completion
if err != nil {
panic(fmt.Errorf("error reading results: %w", err))
}
defer reader.Release()The handle also exposes ID(), Status(ctx), Wait(ctx), and Cancel(ctx).
Usage with local Spice runtime
Follow the quickstart guide to install and run spice locally.
spice := gospice.NewSpiceClient()
defer func() { _ = spice.Close() }()
if err := spice.Init(
gospice.WithHttpAddress("http://127.0.0.1:8090"),
); err != nil {
panic(fmt.Errorf("error initializing SpiceClient: %w", err))
}Or using a custom flight address:
spice := gospice.NewSpiceClient()
defer func() { _ = spice.Close() }()
if err := spice.Init(
gospice.WithFlightAddress("grpc://localhost:50052"),
gospice.WithHttpAddress("http://localhost:8090"),
); err != nil {
panic(fmt.Errorf("error initializing SpiceClient: %w", err))
}Default endpoints
| Target | Arrow Flight | HTTP |
|---|---|---|
| Spice Cloud | flight.spiceai.io:443 | https://data.spiceai.io |
| Local runtime | grpc://127.0.0.1:50051 | http://127.0.0.1:8090 |
These can also be set with the SPICE_FLIGHT_URL, SPICE_HTTP_URL, SPICE_LOCAL_FLIGHT_URL, and SPICE_LOCAL_HTTP_URL environment variables.
Health checks
IsSpiceHealthy(ctx) and IsSpiceReady(ctx) check the HTTP endpoint's /health and /v1/ready routes and return a boolean.
Example
Run go run . to execute a sample query and print the results to the console.
Connection retry
The SpiceClient implements connection retry mechanism (3 attempts by default). The number of attempts can be configured via SetMaxRetries:
spice := gospice.NewSpiceClient()
spice.SetMaxRetries(5) // Setting to 0 will disable retriesRetries are performed for connection and system internal errors. It is the SDK user's responsibility to properly handle other errors, for example RESOURCE_EXHAUSTED (HTTP 429).
Contributing
Contribute to or file an issue with the gospice library at: https://github.com/spiceai/gospice