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

547 lines
10 KiB
Markdown

# 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
```bash
go get github.com/DeBrosOfficial/network/pkg/client
```
## Quick Start
```go
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
```go
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
```go
// Default configuration
cfg := client.DefaultClientConfig()
cfg.GatewayURL = "https://api.orama.network"
cfg.APIKey = "your-api-key"
c := client.NewNetworkClient(cfg)
```
## Authentication
### API Key Authentication
```go
cfg := client.DefaultClientConfig()
cfg.APIKey = "your-api-key-here"
c := client.NewNetworkClient(cfg)
```
### JWT Token Authentication
```go
cfg := client.DefaultClientConfig()
cfg.JWTToken = "your-jwt-token-here"
c := client.NewNetworkClient(cfg)
```
### Obtaining Credentials
```go
// 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
```go
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
```go
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
```go
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
```go
cid := "QmXxx..."
resp, err := c.Storage().Pin(ctx, cid)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Pinned: %s\n", resp.CID)
```
### Unpin File
```go
cid := "QmXxx..."
err := c.Storage().Unpin(ctx, cid)
if err != nil {
log.Fatal(err)
}
fmt.Println("Unpinned successfully")
```
### Check Pin Status
```go
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
```go
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
```go
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
```go
key := "user:123"
err := c.Cache().Delete(ctx, key)
if err != nil {
log.Fatal(err)
}
```
### Multi-Get
```go
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)
```go
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)
```go
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
```go
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
```go
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
```go
topic := "chat"
message := []byte("Hello, everyone!")
err := c.PubSub().Publish(ctx, topic, message)
if err != nil {
log.Fatal(err)
}
```
### Subscribe to Topic
```go
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
```go
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
```go
// 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
```go
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
```go
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
```go
functionName := "hello-world"
err := c.Serverless().Delete(ctx, functionName)
if err != nil {
log.Fatal(err)
}
```
### Get Function Logs
```go
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:
```go
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
```go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
resp, err := c.Storage().Upload(ctx, data, "file.txt")
```
### Retry Logic
```go
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
```go
// 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
```go
// 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:
- GoDoc: https://pkg.go.dev/github.com/DeBrosOfficial/network/pkg/client
- OpenAPI: `openapi/gateway.yaml`
## Support
- GitHub Issues: https://github.com/DeBrosOfficial/network/issues
- Documentation: https://github.com/DeBrosOfficial/network/tree/main/docs