network/docs/CLIENT_SDK.md
2026-01-20 10:03:55 +02:00

10 KiB

Orama Network Client SDK

Overview

The Orama Network Client SDK provides a clean, type-safe Go interface for interacting with the Orama Network. It abstracts away the complexity of HTTP requests, authentication, and error handling.

Installation

go get github.com/DeBrosOfficial/network/pkg/client

Quick Start

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/DeBrosOfficial/network/pkg/client"
)

func main() {
    // Create client configuration
    cfg := client.DefaultClientConfig()
    cfg.GatewayURL = "https://api.orama.network"
    cfg.APIKey = "your-api-key-here"

    // Create client
    c := client.NewNetworkClient(cfg)

    // Use the client
    ctx := context.Background()

    // Upload to storage
    data := []byte("Hello, Orama!")
    resp, err := c.Storage().Upload(ctx, data, "hello.txt")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Uploaded: CID=%s\n", resp.CID)
}

Configuration

ClientConfig

type ClientConfig struct {
    // Gateway URL (e.g., "https://api.orama.network")
    GatewayURL string

    // Authentication (choose one)
    APIKey    string  // API key authentication
    JWTToken  string  // JWT token authentication

    // Client options
    Timeout   time.Duration  // Request timeout (default: 30s)
    UserAgent string         // Custom user agent

    // Network client namespace
    Namespace string  // Default namespace for operations
}

Creating a Client

// Default configuration
cfg := client.DefaultClientConfig()
cfg.GatewayURL = "https://api.orama.network"
cfg.APIKey = "your-api-key"

c := client.NewNetworkClient(cfg)

Authentication

API Key Authentication

cfg := client.DefaultClientConfig()
cfg.APIKey = "your-api-key-here"
c := client.NewNetworkClient(cfg)

JWT Token Authentication

cfg := client.DefaultClientConfig()
cfg.JWTToken = "your-jwt-token-here"
c := client.NewNetworkClient(cfg)

Obtaining Credentials

// 1. Login with wallet signature (not yet implemented in SDK)
// Use the gateway API directly: POST /v1/auth/challenge + /v1/auth/verify

// 2. Issue API key after authentication
// POST /v1/auth/apikey with JWT token

Storage Client

Upload, download, pin, and unpin files to IPFS.

Upload File

data := []byte("Hello, World!")
resp, err := c.Storage().Upload(ctx, data, "hello.txt")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("CID: %s\n", resp.CID)

Upload with Options

opts := &client.StorageUploadOptions{
    Pin:               true,           // Pin after upload
    Encrypt:           true,           // Encrypt before upload
    ReplicationFactor: 3,              // Number of replicas
}
resp, err := c.Storage().UploadWithOptions(ctx, data, "file.txt", opts)

Get File

cid := "QmXxx..."
data, err := c.Storage().Get(ctx, cid)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Downloaded %d bytes\n", len(data))

Pin File

cid := "QmXxx..."
resp, err := c.Storage().Pin(ctx, cid)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Pinned: %s\n", resp.CID)

Unpin File

cid := "QmXxx..."
err := c.Storage().Unpin(ctx, cid)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Unpinned successfully")

Check Pin Status

cid := "QmXxx..."
status, err := c.Storage().Status(ctx, cid)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Status: %s, Replicas: %d\n", status.Status, status.Replicas)

Cache Client

Distributed key-value cache using Olric.

Set Value

key := "user:123"
value := map[string]interface{}{
    "name": "Alice",
    "email": "alice@example.com",
}
ttl := 5 * time.Minute

err := c.Cache().Set(ctx, key, value, ttl)
if err != nil {
    log.Fatal(err)
}

Get Value

key := "user:123"
var user map[string]interface{}
err := c.Cache().Get(ctx, key, &user)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("User: %+v\n", user)

Delete Value

key := "user:123"
err := c.Cache().Delete(ctx, key)
if err != nil {
    log.Fatal(err)
}

Multi-Get

keys := []string{"user:1", "user:2", "user:3"}
results, err := c.Cache().MGet(ctx, keys)
if err != nil {
    log.Fatal(err)
}
for key, value := range results {
    fmt.Printf("%s: %v\n", key, value)
}

Database Client

Query RQLite distributed SQL database.

Execute Query (Write)

sql := "INSERT INTO users (name, email) VALUES (?, ?)"
args := []interface{}{"Alice", "alice@example.com"}

result, err := c.Database().Execute(ctx, sql, args...)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Inserted %d rows\n", result.RowsAffected)

Query (Read)

sql := "SELECT id, name, email FROM users WHERE id = ?"
args := []interface{}{123}

rows, err := c.Database().Query(ctx, sql, args...)
if err != nil {
    log.Fatal(err)
}

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

var users []User
for _, row := range rows {
    var user User
    // Parse row into user struct
    // (manual parsing required, or use ORM layer)
    users = append(users, user)
}

Create Table

schema := `CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`

_, err := c.Database().Execute(ctx, schema)
if err != nil {
    log.Fatal(err)
}

Transaction

tx, err := c.Database().Begin(ctx)
if err != nil {
    log.Fatal(err)
}

_, err = tx.Execute(ctx, "INSERT INTO users (name) VALUES (?)", "Alice")
if err != nil {
    tx.Rollback(ctx)
    log.Fatal(err)
}

_, err = tx.Execute(ctx, "INSERT INTO users (name) VALUES (?)", "Bob")
if err != nil {
    tx.Rollback(ctx)
    log.Fatal(err)
}

err = tx.Commit(ctx)
if err != nil {
    log.Fatal(err)
}

PubSub Client

Publish and subscribe to topics.

Publish Message

topic := "chat"
message := []byte("Hello, everyone!")

err := c.PubSub().Publish(ctx, topic, message)
if err != nil {
    log.Fatal(err)
}

Subscribe to Topic

topic := "chat"
handler := func(ctx context.Context, msg []byte) error {
    fmt.Printf("Received: %s\n", string(msg))
    return nil
}

unsubscribe, err := c.PubSub().Subscribe(ctx, topic, handler)
if err != nil {
    log.Fatal(err)
}

// Later: unsubscribe
defer unsubscribe()

List Topics

topics, err := c.PubSub().ListTopics(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Topics: %v\n", topics)

Serverless Client

Deploy and invoke WebAssembly functions.

Deploy Function

// Read WASM file
wasmBytes, err := os.ReadFile("function.wasm")
if err != nil {
    log.Fatal(err)
}

// Function definition
def := &client.FunctionDefinition{
    Name:        "hello-world",
    Namespace:   "default",
    Description: "Hello world function",
    MemoryLimit: 64, // MB
    Timeout:     30, // seconds
}

// Deploy
fn, err := c.Serverless().Deploy(ctx, def, wasmBytes)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Deployed: %s (CID: %s)\n", fn.Name, fn.WASMCID)

Invoke Function

functionName := "hello-world"
input := map[string]interface{}{
    "name": "Alice",
}

output, err := c.Serverless().Invoke(ctx, functionName, input)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Result: %s\n", output)

List Functions

functions, err := c.Serverless().List(ctx)
if err != nil {
    log.Fatal(err)
}
for _, fn := range functions {
    fmt.Printf("- %s: %s\n", fn.Name, fn.Description)
}

Delete Function

functionName := "hello-world"
err := c.Serverless().Delete(ctx, functionName)
if err != nil {
    log.Fatal(err)
}

Get Function Logs

functionName := "hello-world"
logs, err := c.Serverless().GetLogs(ctx, functionName, 100)
if err != nil {
    log.Fatal(err)
}
for _, log := range logs {
    fmt.Printf("[%s] %s: %s\n", log.Timestamp, log.Level, log.Message)
}

Error Handling

All client methods return typed errors that can be checked:

import "github.com/DeBrosOfficial/network/pkg/errors"

resp, err := c.Storage().Upload(ctx, data, "file.txt")
if err != nil {
    if errors.IsNotFound(err) {
        fmt.Println("Resource not found")
    } else if errors.IsUnauthorized(err) {
        fmt.Println("Authentication failed")
    } else if errors.IsValidation(err) {
        fmt.Println("Validation error")
    } else {
        log.Fatal(err)
    }
}

Advanced Usage

Custom Timeout

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

resp, err := c.Storage().Upload(ctx, data, "file.txt")

Retry Logic

import "github.com/DeBrosOfficial/network/pkg/errors"

maxRetries := 3
for i := 0; i < maxRetries; i++ {
    resp, err := c.Storage().Upload(ctx, data, "file.txt")
    if err == nil {
        break
    }
    if !errors.ShouldRetry(err) {
        return err
    }
    time.Sleep(time.Second * time.Duration(i+1))
}

Multiple Namespaces

// Default namespace
c1 := client.NewNetworkClient(cfg)
c1.Storage().Upload(ctx, data, "file.txt") // Uses default namespace

// Override namespace per request
opts := &client.StorageUploadOptions{
    Namespace: "custom-namespace",
}
c1.Storage().UploadWithOptions(ctx, data, "file.txt", opts)

Testing

Mock Client

// Create a mock client for testing
mockClient := &MockNetworkClient{
    StorageClient: &MockStorageClient{
        UploadFunc: func(ctx context.Context, data []byte, filename string) (*UploadResponse, error) {
            return &UploadResponse{CID: "QmMock"}, nil
        },
    },
}

// Use in tests
resp, err := mockClient.Storage().Upload(ctx, data, "test.txt")
assert.NoError(t, err)
assert.Equal(t, "QmMock", resp.CID)

Examples

See the examples/ directory for complete examples:

  • examples/storage/ - Storage upload/download examples
  • examples/cache/ - Cache operations
  • examples/database/ - Database queries
  • examples/pubsub/ - Pub/sub messaging
  • examples/serverless/ - Serverless functions

API Reference

Complete API documentation is available at:

Support