SDK · Go
Go SDK
github.com/hubfly/hubfly-sdk/go is the official Go client for the Hubfly space platform. It is built on the standard library alone, takes a context.Context on every call, and returns typed responses.
Install
go get github.com/hubfly/hubfly-sdk/goThe module requires Go 1.20 or later and pulls in no third-party dependencies, so it adds nothing to your own dependency graph beyond itself.
Creating a client
hubfly.NewClient takes functional options. With no options it reads the token from the HUBFLY_TOKEN environment variable and talks to the production API.
package main
import (
"context"
"fmt"
"log"
"time"
hubfly "github.com/hubfly/hubfly-sdk/go"
)
func main() {
client := hubfly.NewClient(
hubfly.WithToken("hf_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
hubfly.WithBaseURL("https://api.hubfly.space"),
hubfly.WithTimeout(15*time.Second),
)
ctx := context.Background()
health, err := client.System.Health(ctx)
if err != nil {
log.Fatalf("health check failed: %v", err)
}
fmt.Println("API status:", health.Data.Status)
}| Option | Default | Description |
|---|---|---|
WithToken(string) | $HUBFLY_TOKEN | Personal access token, sent as a bearer token on every request. |
WithBaseURL(string) | https://api.hubfly.space | Override the API host, for example to test against a staging environment. |
WithTimeout(time.Duration) | 30s | Timeout applied to the underlying http.Client. |
WithHTTPClient(*http.Client) | http.DefaultClient | Supply your own client for custom transports, proxies or instrumentation. |
A *hubfly.Client is safe for concurrent use. Build one at start-up and share it, rather than creating a client per request.
Context and timeouts
Every method takes a context.Context as its first argument. Use it to bound a call, or to cancel it when the surrounding request is abandoned. The context deadline wins over WithTimeout when it is shorter.
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
projects, err := client.Projects.List(ctx)
if errors.Is(err, context.DeadlineExceeded) {
// the call ran out of time — safe to retry, GET requests are idempotent
}Response shape
Methods return a typed wrapper around the API envelope, so the resource itself lives under.Data and request metadata under .Meta.
projects, err := client.Projects.List(ctx)
if err != nil {
return err
}
projects.Data // []hubfly.Project
projects.Meta.RequestID // "req_8f3a1d9…" — quote this in support requestsProjects and containers
A project is the isolation boundary; containers live inside it. Container calls take the project ID because every container is scoped to one.
// List every project on the account
projects, err := client.Projects.List(ctx)
// Create a project
project, err := client.Projects.Create(ctx, hubfly.CreateProjectParams{
Name: "backend-api",
Region: "us-east-1",
})
// Deploy a container into it
container, err := client.Containers.Create(ctx, hubfly.CreateContainerParams{
ProjectID: project.Data.ID,
Name: "api-server",
Image: "golang:1.22-alpine",
Ports: []hubfly.PortMapping{
{Container: 8080, Protocol: "tcp"},
},
})
// Lifecycle operations
_, err = client.Containers.Restart(ctx, project.Data.ID, container.Data.ID)Deletes are not recoverable
Projects.Delete tears down every container, volume and reservation in the project. There is no undo and no grace period, so guard it behind a confirmation in any tooling you build.Load balancers
lb, err := client.LoadBalancers.Create(ctx, hubfly.CreateLoadBalancerParams{
ProjectID: "proj_123",
Name: "ingress-lb",
Algorithm: "round_robin",
})
// Remove the balancer when it is no longer needed.
_, err = client.LoadBalancers.Delete(ctx, "proj_123", lb.Data.ID)Networking and firewall
// Private network state for the project
netAccess, err := client.Network.Get(ctx, "proj_123")
// Current ingress firewall configuration
firewall, err := client.Network.GetFirewall(ctx, "proj_123")
for _, rule := range firewall.Data.Rules {
fmt.Printf("%s %s %s -> %s\n",
rule.Direction, rule.Protocol, rule.CIDR, rule.Action)
}Firewall writes are API-only in this SDK release
GetFirewall for inspection. Use the API endpoint explorer for firewall update requests until a typed write method is added.Port reservations
Reserve a public port on the edge, then map it to a container port. The two steps are separate so a reservation survives the container behind it being replaced.
reservation, err := client.Ports.Reserve(ctx, "proj_123", hubfly.ReservePortParams{
Protocol: "tcp",
Port: 6379,
})
// Release it again when the service is gone
_, err = client.Ports.Remove(ctx, "proj_123", reservation.Data.ReservationID)Volumes
A volume is persistent block storage that outlives the container mounted on it.
vol, err := client.Volumes.Create(ctx, hubfly.CreateVolumeParams{
ProjectID: "proj_123",
Name: "redis-data",
SizeGB: 10,
})Hibernation
Hibernating a project stops its containers and releases their memory while keeping volumes and configuration intact. Restoring brings everything back in the same shape.
status, err := client.Hibernation.Hibernate(ctx, "proj_123")
fmt.Println("hibernated:", status.Data.Hibernated)
restored, err := client.Hibernation.Restore(ctx, "proj_123")Developer sub-accounts
Use client.Subaccounts and client.PlatformKeys for tenant control. A client configured with hubfly.WithSubaccount addsX-HubFly-Subaccount to ordinary resource calls made with a platform key.
platform := hubfly.NewClient(
hubfly.WithToken(os.Getenv("HUBFLY_PLATFORM_TOKEN")),
)
created, err := platform.Subaccounts.Create(ctx, hubfly.CreateSubaccountParams{
Name: "Customer 1042",
ExternalRef: "customer_1042",
})
tenant := hubfly.NewClient(
hubfly.WithToken(os.Getenv("HUBFLY_PLATFORM_TOKEN")),
hubfly.WithSubaccount(created.Data.ID),
)
projects, err := tenant.Projects.List(ctx)See Sub-account API for wallet units, idempotency, isolation rules, and lifecycle errors.
Handling errors
API errors come back as a *hubfly.APIError. Unwrap it witherrors.As so the check still works if the error has been wrapped further up the call stack.
_, err := client.Projects.Get(ctx, "proj_does_not_exist")
var apiErr *hubfly.APIError
if errors.As(err, &apiErr) {
fmt.Println("status:", apiErr.StatusCode) // 404
fmt.Println("message:", apiErr.Message) // "Project not found"
fmt.Println("payload:", apiErr.RawPayload) // raw JSON body; may include server details
}Errors and retries covers what each status code means and which failures are worth retrying.
Standard library only
net/http, context andencoding/json. There is nothing to reconcile with the HTTP stack your service already uses, whichever framework it is built on.