Go Integration
This guide demonstrates how to interact with the Surflux gRPC API using Go. Go's strong concurrency support and performance make it an excellent choice for high-throughput blockchain applications.
Overview
Go provides excellent native support for gRPC through the google.golang.org/grpc package. This guide will walk you through setting up a complete Go project for Sui gRPC integration with proper authentication.
Prerequisites
- Go 1.19 or later
- The
protoccompiler (Protocol Buffers compiler)- If you don't have
protocinstalled, you can download it from the official releases page.
- If you don't have
Step 1: Create a New Project
Create a dedicated directory for your Sui gRPC project:
mkdir sui-grpc-go
cd sui-grpc-go
go mod init sui-grpc-go
Step 2: Install Dependencies
Install the required gRPC and Protocol Buffer packages:
go get -u google.golang.org/grpc
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
Step 3: Download and Generate Proto Files
Clone the official Sui proto definitions:
mkdir -p proto
cd proto
git clone https://github.com/MystenLabs/sui-apis.git
Generate Go code from the proto files:
# Inject go_package option (required for Go code generation)
for f in sui-apis/proto/sui/rpc/v2/*.proto; do
if ! grep -q "option go_package" "$f"; then
sed -i 's/package sui.rpc.v2;/package sui.rpc.v2;\noption go_package = "sui-grpc-go\/proto\/sui\/rpc\/v2";/' "$f"
fi
done
# Generate Go code
protoc --go_out=. --go_opt=module=sui-grpc-go \
--go-grpc_out=. --go-grpc_opt=module=sui-grpc-go \
sui-apis/proto/sui/rpc/v2/*.proto
Authentication
Surflux requires authentication via the x-api-key header. We'll implement a custom PerRPCCredentials to automatically inject this header.
Custom Auth Implementation
package main
import (
"context"
)
// apiKeyAuth implements credentials.PerRPCCredentials to inject the API key
type apiKeyAuth struct {
apiKey string
}
// GetRequestMetadata attaches the x-api-key header to every request
func (a *apiKeyAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"x-api-key": a.apiKey,
}, nil
}
// RequireTransportSecurity indicates whether the credentials require TLS
func (a *apiKeyAuth) RequireTransportSecurity() bool {
return true
}
Complete Example
Here's a complete example showing how to connect to Surflux and fetch epoch information:
package main
import (
"context"
"crypto/tls"
"fmt"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
// Import your generated proto package
// pb "sui-grpc-go/proto/sui/rpc/v2"
)
const (
serverAddr = "grpc.surflux.dev:443"
apiKey = "YOUR_API_KEY"
)
// apiKeyAuth implements credentials.PerRPCCredentials
type apiKeyAuth struct {
apiKey string
}
func (a *apiKeyAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"x-api-key": a.apiKey,
}, nil
}
func (a *apiKeyAuth) RequireTransportSecurity() bool {
return true
}
func main() {
// Create TLS credentials
creds := credentials.NewTLS(&tls.Config{
MinVersion: tls.VersionTLS12,
})
// Create connection with TLS and API key auth
conn, err := grpc.Dial(
serverAddr,
grpc.WithTransportCredentials(creds),
grpc.WithPerRPCCredentials(&apiKeyAuth{apiKey: apiKey}),
)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
// Create the client (uncomment when using generated code)
// client := pb.NewLedgerServiceClient(conn)
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Make a request (uncomment when using generated code)
// req := &pb.GetEpochRequest{}
// resp, err := client.GetEpoch(ctx, req)
// if err != nil {
// log.Fatalf("Request failed: %v", err)
// }
fmt.Println("Connection successful! Uncomment the client code above to make requests.")
// Make a request (uncomment when using generated code)
// req := &pb.GetEpochRequest{}
// resp, err := client.GetEpoch(ctx, req)
// if err != nil {
// log.Fatalf("Request failed: %v", err)
// }
// fmt.Printf("Current Epoch: %v\n", resp.Epoch.GetEpoch())
}
Making Requests
Once your proto code is generated, you can make requests to any service:
// Example: Get a checkpoint
req := &pb.GetCheckpointRequest{
CheckpointId: &pb.GetCheckpointRequest_SequenceNumber{
SequenceNumber: 1000,
},
}
resp, err := client.GetCheckpoint(ctx, req)
if err != nil {
log.Fatalf("GetCheckpoint failed: %v", err)
}
fmt.Printf("Checkpoint Digest: %s\n", resp.Checkpoint.GetDigest())
Best Practices
- Connection Pooling: Reuse gRPC connections rather than creating new ones for each request.
- Context Timeouts: Always use context with timeouts to prevent hanging requests.
- Error Handling: Check for both network errors and gRPC status codes.
- Graceful Shutdown: Always close connections when done using
defer conn.Close().
Next Steps
- Explore the generated proto definitions to see all available services and methods
- Implement retry logic for production applications
- Consider using interceptors for logging and monitoring