Installation
Install usinggo get:
go get github.com/trailbaseio/trailbase/client/go/trailbase
Requirements
- Go 1.24.4+
Initialization
Basic Client
package main
import (
"github.com/trailbaseio/trailbase/client/go/trailbase"
)
func main() {
client, err := trailbase.NewClient("https://your-server.trailbase.io")
if err != nil {
panic(err)
}
defer client.Close()
}
Client with Tokens
import "github.com/trailbaseio/trailbase/client/go/trailbase"
refreshToken := "your-refresh-token"
tokens := &trailbase.Tokens{
AuthToken: "your-auth-token",
RefreshToken: &refreshToken,
CsrfToken: nil,
}
client, err := trailbase.NewClientWithTokens(
"https://your-server.trailbase.io",
tokens,
)
if err != nil {
panic(err)
}
defer client.Close()
Authentication
Login
tokens, err := client.Login("[email protected]", "password")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Auth token: %s\n", tokens.AuthToken)
user := client.User()
if user != nil {
fmt.Printf("Logged in as: %s\n", user.Email)
}
Logout
err := client.Logout()
if err != nil {
log.Fatal(err)
}
Current User
user := client.User()
if user != nil {
fmt.Printf("User ID: %s\n", user.Sub)
fmt.Printf("Email: %s\n", user.Email)
}
Access Tokens
tokens := client.Tokens()
if tokens != nil {
// Persist tokens for later use
data, _ := json.Marshal(tokens)
os.WriteFile("tokens.json", data, 0600)
}
Refresh Token
err := client.Refresh()
if err != nil {
log.Fatal(err)
}
Record API
Define Your Record Types
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
AuthorID string `json:"author_id"`
CreatedAt int64 `json:"created_at"`
}
type NewPost struct {
Title string `json:"title"`
Content string `json:"content"`
}
List Records
import "github.com/trailbaseio/trailbase/client/go/trailbase"
posts := trailbase.NewRecordApi(client, "posts")
response, err := posts.List(
&trailbase.ListOptions{
Limit: 10,
Offset: 0,
Order: []string{"-created_at"},
Count: true,
},
)
if err != nil {
log.Fatal(err)
}
var postList []Post
err = json.Unmarshal(response.Records, &postList)
fmt.Printf("Records: %d\n", len(postList))
fmt.Printf("Total count: %v\n", response.TotalCount)
fmt.Printf("Next cursor: %v\n", response.Cursor)
Read a Record
// String ID
data, err := posts.Read("post-id", nil)
if err != nil {
log.Fatal(err)
}
var post Post
err = json.Unmarshal(data, &post)
fmt.Printf("Title: %s\n", post.Title)
Read with Expansion
data, err := posts.Read("post-id", &trailbase.ReadOptions{
Expand: []string{"author"},
})
if err != nil {
log.Fatal(err)
}
var post Post
json.Unmarshal(data, &post)
Create a Record
newPost := NewPost{
Title: "Hello World",
Content: "My first post from Go",
}
postID, err := posts.Create(&newPost)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created post with ID: %s\n", postID)
Create Multiple Records
newPosts := []NewPost{
{Title: "Post 1", Content: "Content 1"},
{Title: "Post 2", Content: "Content 2"},
}
ids, err := posts.CreateBulk(&newPosts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created %d posts\n", len(ids))
Update a Record
update := map[string]interface{}{
"title": "Updated Title",
}
err := posts.Update("post-id", &update)
if err != nil {
log.Fatal(err)
}
Delete a Record
err := posts.Delete("post-id")
if err != nil {
log.Fatal(err)
}
Filtering
import "github.com/trailbaseio/trailbase/client/go/trailbase"
// Simple equality filter
filters := []trailbase.FilterOrComposite{
trailbase.Filter{
Column: "author_id",
Value: userID,
},
}
response, err := posts.List(&trailbase.ListOptions{
Filters: filters,
})
// With comparison operators
weekAgo := time.Now().AddDate(0, 0, -7).Unix()
filters = []trailbase.FilterOrComposite{
trailbase.Filter{
Column: "created_at",
Op: trailbase.CompareOpGreaterThan,
Value: fmt.Sprintf("%d", weekAgo),
},
}
// LIKE operator for text search
filters = []trailbase.FilterOrComposite{
trailbase.Filter{
Column: "title",
Op: trailbase.CompareOpLike,
Value: "%search%",
},
}
// AND composite filter
filters = []trailbase.FilterOrComposite{
trailbase.And{
Filters: []trailbase.FilterOrComposite{
trailbase.Filter{Column: "status", Value: "published"},
trailbase.Filter{Column: "author_id", Value: userID},
},
},
}
// OR composite filter
filters = []trailbase.FilterOrComposite{
trailbase.Or{
Filters: []trailbase.FilterOrComposite{
trailbase.Filter{Column: "category", Value: "tech"},
trailbase.Filter{Column: "category", Value: "science"},
},
},
}
Available Comparison Operators
const (
CompareOpEqual CompareOp = "$eq"
CompareOpNotEqual CompareOp = "$ne"
CompareOpLessThan CompareOp = "$lt"
CompareOpLessThanEqual CompareOp = "$lte"
CompareOpGreaterThan CompareOp = "$gt"
CompareOpGreaterThanEqual CompareOp = "$gte"
CompareOpLike CompareOp = "$like"
CompareOpRegexp CompareOp = "$re"
CompareOpStWithin CompareOp = "@within" // Geospatial
CompareOpStIntersects CompareOp = "@intersects" // Geospatial
CompareOpStContains CompareOp = "@contains" // Geospatial
)
Error Handling
data, err := posts.Read("post-id", nil)
if err != nil {
if httpErr, ok := err.(*trailbase.HttpError); ok {
fmt.Printf("HTTP %d: %s\n", httpErr.StatusCode, httpErr.Message)
} else {
fmt.Printf("Error: %v\n", err)
}
return
}
var post Post
json.Unmarshal(data, &post)
Type Definitions
User
type User struct {
Sub string
Email string
}
Tokens
type Tokens struct {
AuthToken string `json:"auth_token"`
RefreshToken *string `json:"refresh_token,omitempty"`
CsrfToken *string `json:"csrf_token,omitempty"`
}
ListResponse
type ListResponse struct {
Cursor *string `json:"cursor,omitempty"`
TotalCount *int `json:"total_count,omitempty"`
Records json.RawMessage `json:"records"`
}
ListOptions
type ListOptions struct {
Pagination *Pagination
Order []string
Filters []FilterOrComposite
Count bool
Expand []string
}
Pagination
type Pagination struct {
Cursor *string
Limit *int
Offset *int
}
Best Practices
Always check errors returned by SDK methods. Go’s explicit error handling ensures you don’t miss failure cases.
Store tokens securely and never commit them to version control. Consider using environment variables or secure credential storage.
The client automatically refreshes auth tokens before they expire through concurrent-safe token management.
Example Application
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"github.com/trailbaseio/trailbase/client/go/trailbase"
)
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Published bool `json:"published"`
}
func main() {
// Initialize client
url := os.Getenv("TRAILBASE_URL")
if url == "" {
url = "http://localhost:4000"
}
client, err := trailbase.NewClient(url)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Login
_, err = client.Login(
os.Getenv("TRAILBASE_EMAIL"),
os.Getenv("TRAILBASE_PASSWORD"),
)
if err != nil {
log.Fatal("Login failed:", err)
}
if user := client.User(); user != nil {
fmt.Printf("Logged in as: %s\n", user.Email)
}
// List posts
posts := trailbase.NewRecordApi(client, "posts")
response, err := posts.List(&trailbase.ListOptions{
Order: []string{"-created_at"},
Pagination: &trailbase.Pagination{
Limit: intPtr(10),
},
Filters: []trailbase.FilterOrComposite{
trailbase.Filter{
Column: "published",
Value: "true",
},
},
})
if err != nil {
log.Fatal(err)
}
var postList []Post
json.Unmarshal(response.Records, &postList)
fmt.Printf("\nFound %d posts:\n", len(postList))
for _, post := range postList {
fmt.Printf("- %s\n", post.Title)
}
// Create a new post
newPost := map[string]interface{}{
"title": "Hello from Go",
"content": "This post was created using the TrailBase Go SDK",
"published": true,
}
newPostID, err := posts.Create(&newPost)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nCreated new post with ID: %s\n", newPostID)
// Read the post
data, err := posts.Read(newPostID, nil)
if err != nil {
log.Fatal(err)
}
var post Post
json.Unmarshal(data, &post)
fmt.Printf("Post title: %s\n", post.Title)
// Logout
err = client.Logout()
if err != nil {
log.Fatal(err)
}
fmt.Println("\nLogged out")
}
func intPtr(i int) *int {
return &i
}