Client Types
This page documents the types available in the client package for JSON-RPC communication, subscriptions, and server functionality.
Client Types
Client
The Client type represents a JSON-RPC client connection. It is the primary type for making RPC calls to Starknet nodes.
Type Definition
type Client struct {
// Internal fields are not directly accessible
}Creation
Create a Client using the package-level functions:
// HTTP connection
client, err := client.DialHTTP("https://starknet-sepolia.public.blastapi.io/rpc/v0_8")
// WebSocket connection
client, err := client.DialWebsocket(ctx, "wss://starknet-sepolia.public.blastapi.io/rpc/v0_8/ws", "")Methods
Call(result, method, args...)- Make a JSON-RPC callCallContext(ctx, result, method, args...)- Make a context-aware JSON-RPC callSubscribe(ctx, namespace, methodSuffix, channel, args...)- Create a subscriptionBatchCall(batch)- Execute multiple requests in a batchClose()- Close the client connection
See Client Methods for detailed documentation.
Usage Example
package main
import (
"context"
"fmt"
"log"
"github.com/NethermindEth/starknet.go/client"
)
func main() {
// Create client
c, err := client.DialHTTP("https://starknet-sepolia.public.blastapi.io/rpc/v0_8")
if err != nil {
log.Fatal(err)
}
defer c.Close()
// Use client
var result string
err = c.CallContext(context.Background(), &result, "starknet_specVersion")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Spec Version: %s\n", result)
}ClientOption
ClientOption is a function type used to configure the Client during creation.
Type Definition
type ClientOption func(*Client)Available Options
While specific options depend on the implementation, common patterns include:
WithHTTPClient(httpClient)- Use a custom HTTP clientWithHeader(key, value)- Add default headersWithWebsocketDialer(dialer)- Use a custom WebSocket dialer
Usage Example
package main
import (
"net/http"
"time"
"github.com/NethermindEth/starknet.go/client"
)
func main() {
// Create custom HTTP client with timeout
httpClient := &http.Client{
Timeout: 30 * time.Second,
}
// Create client with options
c, err := client.DialHTTPWithOptions(
"https://starknet-sepolia.public.blastapi.io/rpc/v0_8",
client.WithHTTPClient(httpClient),
client.WithHeader("User-Agent", "MyApp/1.0"),
)
if err != nil {
log.Fatal(err)
}
defer c.Close()
}Subscription Types
ClientSubscription
ClientSubscription represents an active subscription on the client side. It provides methods to manage the subscription lifecycle and receive errors.
Type Definition
type ClientSubscription struct {
// Internal fields are not directly accessible
}Methods
Unsubscribe
func (sub *ClientSubscription) Unsubscribe()Cancels the subscription and closes the notification channel.
Err
func (sub *ClientSubscription) Err() <-chan errorReturns a channel that receives any error that caused the subscription to end.
ID
func (sub *ClientSubscription) ID() IDReturns the unique identifier for this subscription.
Usage Example
package main
import (
"context"
"fmt"
"log"
"github.com/NethermindEth/starknet.go/client"
)
func main() {
c, err := client.DialWebsocket(context.Background(), "wss://starknet-sepolia.public.blastapi.io/rpc/v0_8/ws", "")
if err != nil {
log.Fatal(err)
}
defer c.Close()
headers := make(chan map[string]interface{})
sub, err := c.Subscribe(context.Background(), "starknet", "subscribeNewHeads", headers)
if err != nil {
log.Fatal(err)
}
defer sub.Unsubscribe()
fmt.Printf("Subscription ID: %v\n", sub.ID())
for {
select {
case header := <-headers:
fmt.Printf("New block: %v\n", header)
case err := <-sub.Err():
if err != nil {
log.Printf("Subscription error: %v\n", err)
}
return
}
}
}Subscription
Subscription is the server-side representation of a subscription, created by a Notifier.
Type Definition
type Subscription struct {
ID ID
namespace string
// Internal fields
}Fields
ID- Unique identifier for the subscriptionnamespace- The RPC namespace for this subscription
Usage Example
This type is typically used on the server side when implementing RPC services with subscription support.
package main
import (
"context"
"log"
"github.com/NethermindEth/starknet.go/client"
)
type BlockService struct{}
func (s *BlockService) SubscribeNewHeads(ctx context.Context) (*client.Subscription, error) {
notifier, ok := client.NotifierFromContext(ctx)
if !ok {
return nil, fmt.Errorf("no notifier in context")
}
// Create subscription
sub := notifier.CreateSubscription()
// Send notifications in background
go func() {
for {
// Get new block header...
err := notifier.Notify(sub.ID, blockHeader)
if err != nil {
return
}
}
}()
return sub, nil
}ReorgEvent
ReorgEvent represents a blockchain reorganization event in a subscription stream.
Type Definition
type ReorgEvent struct {
OldChain []interface{}
NewChain []interface{}
}Fields
OldChain- The blocks that were removed from the chainNewChain- The new blocks that replaced the old chain
Usage Example
package main
import (
"context"
"fmt"
"log"
"github.com/NethermindEth/starknet.go/client"
)
func main() {
c, err := client.DialWebsocket(context.Background(), "wss://starknet-sepolia.public.blastapi.io/rpc/v0_8/ws", "")
if err != nil {
log.Fatal(err)
}
defer c.Close()
events := make(chan interface{})
sub, err := c.Subscribe(context.Background(), "starknet", "subscribeNewHeads", events)
if err != nil {
log.Fatal(err)
}
defer sub.Unsubscribe()
for event := range events {
switch e := event.(type) {
case map[string]interface{}:
fmt.Printf("New block: %v\n", e)
case *client.ReorgEvent:
fmt.Printf("Reorg detected!\n")
fmt.Printf(" Old chain: %v\n", e.OldChain)
fmt.Printf(" New chain: %v\n", e.NewChain)
}
}
}Handling Reorgs
When a reorganization occurs:
- The subscription channel receives a
ReorgEvent - Old blocks in
OldChainshould be considered invalid - New blocks in
NewChainrepresent the current canonical chain - Applications should update their state accordingly
Server Types
Server
Server represents a JSON-RPC server that can handle HTTP and WebSocket requests.
Type Definition
type Server struct {
// Internal fields are not directly accessible
}Creation
server := client.NewServer()Methods
RegisterName
func (s *Server) RegisterName(name string, receiver interface{}) errorRegisters a service with the given name. All exported methods of the receiver become available as RPC methods.
ServeHTTP
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)Handles HTTP requests. Implements the http.Handler interface.
WebsocketHandler
func (s *Server) WebsocketHandler(allowedOrigins []string) http.HandlerReturns an HTTP handler for WebSocket connections.
Usage Example
package main
import (
"log"
"net/http"
"github.com/NethermindEth/starknet.go/client"
)
// CalculatorService provides math operations
type CalculatorService struct{}
func (c *CalculatorService) Add(a, b int) int {
return a + b
}
func (c *CalculatorService) Multiply(a, b int) int {
return a * b
}
func main() {
// Create server
server := client.NewServer()
// Register service
err := server.RegisterName("calculator", new(CalculatorService))
if err != nil {
log.Fatal(err)
}
// Set up HTTP handlers
http.Handle("/rpc", server)
http.Handle("/ws", server.WebsocketHandler([]string{"*"}))
// Start server
log.Println("RPC server listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}Service Registration
Services must follow these rules:
- Methods must be exported (start with uppercase letter)
- Methods can return
erroras the last return value - Methods can accept
context.Contextas the first parameter - All parameters and return values must be JSON-serializable
Example service:
type MyService struct{}
// Valid RPC method
func (s *MyService) GetData(id int) (string, error) {
return "data", nil
}
// Valid with context
func (s *MyService) GetDataWithContext(ctx context.Context, id int) (string, error) {
return "data", nil
}
// Invalid - not exported
func (s *MyService) privateMethod() {}
// Invalid - no return value
func (s *MyService) SetData(data string) {}Notifier
Notifier is used on the server side to send notifications to subscribed clients.
Type Definition
type Notifier struct {
// Internal fields are not directly accessible
}Methods
CreateSubscription
func (n *Notifier) CreateSubscription() *SubscriptionCreates a new subscription that can receive notifications.
Notify
func (n *Notifier) Notify(id ID, data interface{}) errorSends a notification to the subscription with the given ID.
Closed
func (n *Notifier) Closed() <-chan interface{}Returns a channel that's closed when the client disconnects.
Usage Example
package main
import (
"context"
"fmt"
"time"
"github.com/NethermindEth/starknet.go/client"
)
type EventService struct{}
func (s *EventService) Subscribe(ctx context.Context, eventType string) (*client.Subscription, error) {
// Get notifier from context
notifier, ok := client.NotifierFromContext(ctx)
if !ok {
return nil, fmt.Errorf("no notifier in context")
}
// Create subscription
sub := notifier.CreateSubscription()
// Send notifications
go func() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// Send event notification
event := map[string]interface{}{
"type": eventType,
"timestamp": time.Now().Unix(),
}
err := notifier.Notify(sub.ID, event)
if err != nil {
return
}
case <-notifier.Closed():
// Client disconnected
return
}
}
}()
return sub, nil
}Utility Types
PeerInfo
PeerInfo contains information about a peer connection.
Type Definition
type PeerInfo struct {
Transport string
RemoteAddr string
HTTP struct {
Version string
// HTTP-specific fields
}
}Fields
Transport- The transport protocol (http, ws, ipc)RemoteAddr- The remote address of the peerHTTP- HTTP-specific information
Usage Example
package main
import (
"context"
"fmt"
"github.com/NethermindEth/starknet.go/client"
)
type InfoService struct{}
func (s *InfoService) GetConnectionInfo(ctx context.Context) (map[string]string, error) {
peerInfo, ok := client.PeerInfoFromContext(ctx)
if !ok {
return nil, fmt.Errorf("no peer info available")
}
info := map[string]string{
"transport": peerInfo.Transport,
"remote_addr": peerInfo.RemoteAddr,
}
if peerInfo.Transport == "http" {
info["http_version"] = peerInfo.HTTP.Version
}
return info, nil
}ID
ID represents a unique identifier for subscriptions.
Type Definition
type ID stringCreation
id := client.NewID()Usage
IDs are primarily used internally for subscription management but may be useful when building custom RPC servers or debugging subscription issues.
BatchElem
BatchElem represents a single element in a batch request.
Type Definition
type BatchElem struct {
Method string
Args []interface{}
Result interface{}
Error error
}Fields
Method- The JSON-RPC method name to callArgs- Slice of arguments for the methodResult- Pointer to store the resultError- Error for this specific call (populated after batch execution)
Usage Example
package main
import (
"fmt"
"log"
"github.com/NethermindEth/starknet.go/client"
)
func main() {
c, err := client.DialHTTP("https://starknet-sepolia.public.blastapi.io/rpc/v0_8")
if err != nil {
log.Fatal(err)
}
defer c.Close()
var (
version string
chainID string
blockNum uint64
)
batch := []client.BatchElem{
{
Method: "starknet_specVersion",
Args: []interface{}{},
Result: &version,
},
{
Method: "starknet_chainId",
Args: []interface{}{},
Result: &chainID,
},
{
Method: "starknet_blockNumber",
Args: []interface{}{},
Result: &blockNum,
},
}
err = c.BatchCall(batch)
if err != nil {
log.Fatal("Batch failed:", err)
}
// Check individual errors
for i, elem := range batch {
if elem.Error != nil {
fmt.Printf("Call %d failed: %v\n", i, elem.Error)
}
}
fmt.Printf("Version: %s, Chain: %s, Block: %d\n", version, chainID, blockNum)
}Error Types
HTTPError
HTTPError represents an HTTP-specific error.
Type Definition
type HTTPError struct {
StatusCode int
Status string
Body []byte
}Usage Example
package main
import (
"errors"
"fmt"
"github.com/NethermindEth/starknet.go/client"
)
func handleError(err error) {
var httpErr *client.HTTPError
if errors.As(err, &httpErr) {
fmt.Printf("HTTP Error %d: %s\n", httpErr.StatusCode, httpErr.Status)
fmt.Printf("Response body: %s\n", httpErr.Body)
return
}
// Handle other errors
fmt.Printf("Error: %v\n", err)
}Type Relationships
Client
├── Call() -> error
├── CallContext() -> error
├── Subscribe() -> *ClientSubscription, error
├── BatchCall([]BatchElem) -> error
└── Close()
ClientSubscription
├── Unsubscribe()
├── Err() -> <-chan error
└── ID() -> ID
Server
├── RegisterName()
├── ServeHTTP()
└── WebsocketHandler() -> http.Handler
Notifier
├── CreateSubscription() -> *Subscription
├── Notify(ID, interface{}) -> error
└── Closed() -> <-chan interface{}Best Practices
Type Safety
Always use proper types for results:
// Good: Type-safe result
var blockNumber uint64
c.CallContext(ctx, &blockNumber, "starknet_blockNumber")
// Avoid: Using interface{}
var result interface{}
c.CallContext(ctx, &result, "starknet_blockNumber")
blockNumber := result.(uint64) // Type assertion requiredError Handling
Check both batch errors and individual element errors:
err := c.BatchCall(batch)
if err != nil {
// Entire batch failed
return err
}
for i, elem := range batch {
if elem.Error != nil {
// Individual call failed
log.Printf("Call %d failed: %v", i, elem.Error)
}
}Resource Management
Always clean up subscriptions and clients:
// Client
c, err := client.DialHTTP(url)
if err != nil {
return err
}
defer c.Close()
// Subscription
sub, err := c.Subscribe(ctx, ns, method, ch)
if err != nil {
return err
}
defer sub.Unsubscribe()Related Documentation
- Client Functions - Functions for creating clients and managing context
- Client Methods - Methods for making RPC calls and managing subscriptions
- Client Overview - Package overview and quick start guide
- RPC Methods - High-level Starknet RPC method wrappers

