Go Client Reference
The client package provides a typed Go client for st8d.
Installation
Section titled “Installation”go get github.com/geeper-io/st8/clientCreating a client
Section titled “Creating a client”import st8 "github.com/geeper-io/st8/client"
// Basic clientc := st8.NewHTTP("https://st8.internal")
// With authenticationc := st8.NewHTTP("https://st8.internal", st8.WithToken("your-token"),)
// With request timeoutc := st8.NewHTTP("https://st8.internal", st8.WithToken("your-token"), st8.WithTimeout(5*time.Second),)Every operation targets a scope: a namespace + branch combination.
type Scope struct { Namespace string `json:"namespace"` Branch string `json:"branch"`}Document
Section titled “Document”A named blob of content. Value is an arbitrary string (typically JSON).
type Document struct { Key string `json:"key"` Value string `json:"value"`}ApplyResult
Section titled “ApplyResult”type ApplyResult struct { RevisionID int64 `json:"revision_id"` Noop bool `json:"noop"` // true if nothing changed Changes []Change `json:"changes"`}
type Change struct { Key string `json:"key"` Old string `json:"old"` // empty for new keys New string `json:"new"` // empty for deleted keys}GetResult
Section titled “GetResult”type GetResult struct { RevisionID int64 `json:"revision_id"` Objects map[string]string `json:"objects"`}LogEntry
Section titled “LogEntry”type LogEntry struct { RevisionID int64 `json:"revision_id"` Message string `json:"message"` CreatedAt time.Time `json:"created_at"` Changes []Change `json:"changes"`}Methods
Section titled “Methods”Write one or more documents. Creates a new revision if any document changed.
func (c *HTTP) Apply(ctx context.Context, input ApplyInput) (*ApplyResult, error)
type ApplyInput struct { Scope Scope `json:"scope"` Documents []Document `json:"documents"` Message string `json:"message"`}Example:
result, err := client.Apply(ctx, st8.ApplyInput{ Scope: st8.Scope{Namespace: "myapp/prod", Branch: "main"}, Message: "enable dark mode", Documents: []st8.Document{ {Key: "feature_flags", Value: `{"dark_mode":true}`}, },})if err != nil { return err}if result.Noop { fmt.Println("nothing changed")} else { fmt.Printf("created revision %d\n", result.RevisionID)}Fetch the current state of a namespace/branch.
func (c *HTTP) Get(ctx context.Context, scope Scope, revision int64, checkpoint string) (*GetResult, error)- Pass
revision = 0andcheckpoint = ""to get the latest revision. - Pass a revision ID to get historical state.
- Pass a checkpoint name to get the revision named by that checkpoint.
Example:
result, err := client.Get(ctx, st8.Scope{ Namespace: "myapp/prod", Branch: "main",}, 0, "")if err != nil { return err}raw := result.Objects["feature_flags"] // e.g. `{"dark_mode":true}`DiffDocuments
Section titled “DiffDocuments”Check what would change if the given documents were applied, without applying them.
func (c *HTTP) DiffDocuments(ctx context.Context, scope Scope, revision int64, checkpoint string, docs []Document) (*DiffResult, error)Checkpoint
Section titled “Checkpoint”Create a named checkpoint at the current revision.
func (c *HTTP) Checkpoint(ctx context.Context, scope Scope, name, description string) (*CheckpointResult, error)Rollback
Section titled “Rollback”Roll back to a previous revision or checkpoint.
func (c *HTTP) Rollback(ctx context.Context, scope Scope, revision int64, checkpoint, message string) (*ApplyResult, error)Retrieve revision history.
func (c *HTTP) Log(ctx context.Context, scope Scope, limit int) ([]LogEntry, error)CreateBranch
Section titled “CreateBranch”Create a new branch, optionally based on a specific revision or checkpoint.
func (c *HTTP) CreateBranch(ctx context.Context, scope Scope, name string, revision int64, checkpoint string) (*BranchResult, error)ListBranches
Section titled “ListBranches”List all branches in a namespace.
func (c *HTTP) ListBranches(ctx context.Context, scope Scope) ([]BranchListEntry, error)Restore
Section titled “Restore”Restore the current scope from another branch, revision, or checkpoint.
func (c *HTTP) Restore(ctx context.Context, input RestoreInput) (*ApplyResult, error)
type RestoreInput struct { Scope Scope `json:"scope"` FromRevision int64 `json:"from_revision"` FromCheckpoint string `json:"from_checkpoint"` FromBranch string `json:"from_branch"` Message string `json:"message"`}Run garbage collection. Pass keep to retain the most recent N revisions per namespace/branch.
func (c *HTTP) GC(ctx context.Context, keep int) (*GCResult, error)
type GCResult struct { Pruned int `json:"pruned"`}Error handling
Section titled “Error handling”All methods return a non-nil error on failure. HTTP errors (4xx, 5xx) are returned as error values with the server’s message included.
result, err := client.Get(ctx, scope, 0, "")if err != nil { // err.Error() includes HTTP status and server message // e.g. "request failed with status 401 Unauthorized: unauthorized" log.Fatal(err)}Always use a context with a deadline or timeout in production:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)defer cancel()result, err := client.Get(ctx, scope, 0, "")Or set a default timeout on the client:
c := st8.NewHTTP(url, st8.WithToken(token), st8.WithTimeout(2*time.Second))The Client interface
Section titled “The Client interface”The client package exports a Client interface satisfied by *HTTP. Use it to simplify testing:
type Client interface { Apply(ctx context.Context, input ApplyInput) (*ApplyResult, error) Get(ctx context.Context, scope Scope, revision int64, checkpoint string) (*GetResult, error) DiffDocuments(ctx context.Context, scope Scope, revision int64, checkpoint string, docs []Document) (*DiffResult, error) Checkpoint(ctx context.Context, scope Scope, name, description string) (*CheckpointResult, error) Rollback(ctx context.Context, scope Scope, revision int64, checkpoint, message string) (*ApplyResult, error) Log(ctx context.Context, scope Scope, limit int) ([]LogEntry, error) CreateBranch(ctx context.Context, scope Scope, name string, revision int64, checkpoint string) (*BranchResult, error) ListBranches(ctx context.Context, scope Scope) ([]BranchListEntry, error) Restore(ctx context.Context, input RestoreInput) (*ApplyResult, error) GC(ctx context.Context, keep int) (*GCResult, error)}