goapitosdk

package module
v1.2.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2025 License: MIT Imports: 9 Imported by: 0

README ΒΆ

Go Apito SDK

Go Reference Go Report Card

A comprehensive Go SDK for communicating with Apito GraphQL API endpoints. This SDK implements the InjectedDBOperationInterface and provides both type-safe and flexible interfaces for interacting with Apito's backend services.

πŸš€ Features

  • βœ… Complete SDK Implementation: Full implementation of InjectedDBOperationInterface
  • βœ… Type-Safe Operations: Generic typed methods for better development experience
  • βœ… GraphQL-Based: Native GraphQL communication with Apito backend
  • βœ… Authentication Ready: API key and tenant-based authentication
  • βœ… Context-Aware: Full context support with timeout and cancellation
  • βœ… Comprehensive Error Handling: Detailed error responses and GraphQL error support
  • βœ… Plugin-Ready: Perfect for HashiCorp Go plugins and microservices
  • βœ… Production Ready: Battle-tested in production environments

πŸ“¦ Installation

go get github.com/apito-io/go-internal-sdk

🎯 Quick Start

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    goapitosdk "github.com/apito-io/go-internal-sdk"
)

func main() {
    // Create a new client
    client := goapitosdk.NewClient(goapitosdk.Config{
        BaseURL: "https://api.apito.io/graphql",
        APIKey:  "your-api-key-here",
        Timeout: 30 * time.Second,
    })

    ctx := context.Background()

    // Create a new todo
    todoData := map[string]interface{}{
        "title":       "Learn Apito SDK",
        "description": "Complete the SDK tutorial",
        "status":      "todo",
        "priority":    "high",
    }

    request := &goapitosdk.CreateAndUpdateRequest{
        Model:   "todos",
        Payload: todoData,
    }

    todo, err := client.CreateNewResource(ctx, request)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created todo: %s\n", todo.ID)
}

βš™οΈ Configuration

Basic Configuration
client := goapitosdk.NewClient(goapitosdk.Config{
    BaseURL: "https://api.apito.io/graphql",  // Your Apito GraphQL endpoint
    APIKey:  "your-api-key-here",             // X-APITO-KEY header value
    Timeout: 30 * time.Second,                // HTTP client timeout
})
Advanced Configuration
// Custom HTTP client with specific settings
customClient := &http.Client{
    Timeout: 60 * time.Second,
    Transport: &http.Transport{
        MaxIdleConns:        100,
        MaxIdleConnsPerHost: 10,
        IdleConnTimeout:     90 * time.Second,
    },
}

client := goapitosdk.NewClient(goapitosdk.Config{
    BaseURL:    "https://api.apito.io/graphql",
    APIKey:     "your-api-key-here",
    HTTPClient: customClient,
})
Context with Tenant ID
ctx := context.Background()
ctx = context.WithValue(ctx, "tenant_id", "your-tenant-id")

// All operations will now include the tenant ID
results, err := client.SearchResources(ctx, "users", filter, false)

πŸ“š Complete API Reference

πŸ” Authentication
Generate Tenant Token

Generate a new tenant token for multi-tenant operations:

tenantToken, err := client.GenerateTenantToken(ctx, "auth-token", "tenant-id")
if err != nil {
    log.Fatal(err)
}
fmt.Println("Generated token:", tenantToken)
πŸ“ Resource Management
Create New Resource

Untyped Creation:

request := &goapitosdk.CreateAndUpdateRequest{
    Model: "users",
    Payload: map[string]interface{}{
        "name":   "John Doe",
        "email":  "john@example.com",
        "active": true,
    },
    Connect: map[string]interface{}{
        "organization_id": "org-123",
    },
}

user, err := client.CreateNewResource(ctx, request)

Type-Safe Creation:

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

typedUser, err := goapitosdk.CreateNewResourceTyped[User](client, ctx, request)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Created user: %s (%s)\n", typedUser.Data.Name, typedUser.Data.Email)
Update Resource
updateRequest := &goapitosdk.CreateAndUpdateRequest{
    ID:    "user-123",
    Model: "users",
    Payload: map[string]interface{}{
        "name": "Jane Doe Updated",
    },
    Connect: map[string]interface{}{
        "role_id": "role-456",
    },
    Disconnect: map[string]interface{}{
        "old_role_id": "role-123",
    },
    ForceUpdate: false,
}

updatedUser, err := client.UpdateResource(ctx, updateRequest)
Delete Resource
err := client.DeleteResource(ctx, "users", "user-123")
if err != nil {
    log.Fatal(err)
}
πŸ” Search & Retrieval
Search Resources

Basic Search:

filter := map[string]interface{}{
    "limit": 10,
    "page":  1,
    "where": map[string]interface{}{
        "status": "active",
        "role":   "admin",
    },
    "search": "john@example.com",
}

results, err := client.SearchResources(ctx, "users", filter, false)

Type-Safe Search:

typedResults, err := goapitosdk.SearchResourcesTyped[User](client, ctx, "users", filter, false)
if err != nil {
    log.Fatal(err)
}

for _, userDoc := range typedResults.Results {
    fmt.Printf("User: %s (%s)\n", userDoc.Data.Name, userDoc.Data.Email)
}

Advanced Filtering:

advancedFilter := map[string]interface{}{
    "limit":  20,
    "offset": 10,
    "where": map[string]interface{}{
        "created_at": map[string]interface{}{
            "$gte": "2024-01-01T00:00:00Z",
        },
        "status": map[string]interface{}{
            "$in": []string{"active", "pending"},
        },
    },
    "sort": map[string]interface{}{
        "created_at": -1, // Descending order
    },
}

results, err := client.SearchResources(ctx, "users", advancedFilter, false)
Get Single Resource

Untyped Retrieval:

user, err := client.GetSingleResource(ctx, "users", "user-123", false)
if err != nil {
    log.Fatal(err)
}

Type-Safe Retrieval:

typedUser, err := goapitosdk.GetSingleResourceTyped[User](client, ctx, "users", "user-123", false)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("User: %s\n", typedUser.Data.Name)
relationConnection := map[string]interface{}{
    "model": "todos",
    "filter": map[string]interface{}{
        "limit": 10,
        "where": map[string]interface{}{
            "status": "pending",
        },
    },
}

// Get todos related to a user
relatedTodos, err := client.GetRelationDocuments(ctx, "user-123", relationConnection)
if err != nil {
    log.Fatal(err)
}

// Type-safe version
typedTodos, err := goapitosdk.GetRelationDocumentsTyped[Todo](client, ctx, "user-123", relationConnection)
πŸ“Š Audit & Debug
Send Audit Log
auditData := goapitosdk.AuditData{
    Resource: "users",
    Action:   "create",
    Author: map[string]interface{}{
        "user_id": "admin-123",
        "name":    "Admin User",
    },
    Data: map[string]interface{}{
        "user_id": "user-456",
        "email":   "newuser@example.com",
    },
    Meta: map[string]interface{}{
        "ip_address": "192.168.1.1",
        "user_agent": "Apito-SDK/1.0",
        "timestamp":  time.Now().Format(time.RFC3339),
    },
}

err := client.SendAuditLog(ctx, auditData)
if err != nil {
    log.Fatal(err)
}
Debug Operations
debugData := map[string]interface{}{
    "operation": "user_creation",
    "duration":  "150ms",
    "success":   true,
}

result, err := client.Debug(ctx, "user_management", debugData)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Debug result: %+v\n", result)

🎯 Complete Todo Example

The SDK includes a comprehensive todo application example that demonstrates all features:

# Set environment variables
export APITO_BASE_URL="https://api.apito.io/graphql"
export APITO_API_KEY="your-api-key"
export APITO_TENANT_ID="your-tenant-id"  # Optional
export APITO_AUTH_TOKEN="your-auth-token"  # Optional for token generation

# Run the example
cd examples/basic
go run main.go

The example demonstrates:

  • πŸ” Authentication & tenant token generation
  • πŸ“ Creating resources (todos, users, categories)
  • πŸ” Searching with both typed and untyped methods
  • πŸ“„ Getting single resources
  • ✏️ Updating resources
  • πŸ”— Getting related documents
  • πŸ“Š Audit logging
  • πŸ› Debug functionality
  • πŸ—‘οΈ Resource cleanup

πŸ—οΈ Type System

Defining Custom Types
// Define your data structures
type Todo struct {
    ID          string    `json:"id"`
    Title       string    `json:"title"`
    Description string    `json:"description"`
    Status      string    `json:"status"`
    Priority    string    `json:"priority"`
    DueDate     time.Time `json:"due_date"`
    CreatedAt   time.Time `json:"created_at"`
    UpdatedAt   time.Time `json:"updated_at"`
}

type User struct {
    ID       string `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
    Role     string `json:"role"`
    Active   bool   `json:"active"`
}
Type-Safe Operations

All operations have type-safe counterparts:

// Type-safe alternatives
GetSingleResourceTyped[T](client, ctx, model, id, singlePageData)
SearchResourcesTyped[T](client, ctx, model, filter, aggregate)
GetRelationDocumentsTyped[T](client, ctx, id, connection)
CreateNewResourceTyped[T](client, ctx, request)
UpdateResourceTyped[T](client, ctx, request)

πŸ”Œ Plugin Integration

HashiCorp Go Plugin Usage
// In your plugin
type MyPlugin struct {
    client goapitosdk.InjectedDBOperationInterface
}

func (p *MyPlugin) Initialize(client goapitosdk.InjectedDBOperationInterface) {
    p.client = client
}

func (p *MyPlugin) ProcessData(ctx context.Context) error {
    // Use the client for database operations
    results, err := p.client.SearchResources(ctx, "data", filter, false)
    if err != nil {
        return err
    }

    // Process results...
    return nil
}
Microservice Integration
// In your microservice
type UserService struct {
    apitoClient *goapitosdk.Client
}

func NewUserService(config goapitosdk.Config) *UserService {
    return &UserService{
        apitoClient: goapitosdk.NewClient(config),
    }
}

func (s *UserService) CreateUser(ctx context.Context, userData User) (*User, error) {
    request := &goapitosdk.CreateAndUpdateRequest{
        Model:   "users",
        Payload: structToMap(userData),
    }

    result, err := goapitosdk.CreateNewResourceTyped[User](s.apitoClient, ctx, request)
    if err != nil {
        return nil, err
    }

    return &result.Data, nil
}

πŸ”§ Error Handling

GraphQL Errors
results, err := client.SearchResources(ctx, "users", filter, false)
if err != nil {
    // Check if it's a GraphQL error
    if graphqlErr, ok := err.(*goapitosdk.GraphQLError); ok {
        fmt.Printf("GraphQL Error: %s\n", graphqlErr.Message)
        fmt.Printf("Path: %v\n", graphqlErr.Path)
        fmt.Printf("Extensions: %v\n", graphqlErr.Extensions)
    } else {
        // Handle other errors (HTTP, network, etc.)
        fmt.Printf("Error: %v\n", err)
    }
}
HTTP Errors
// Handle HTTP-level errors
client := goapitosdk.NewClient(goapitosdk.Config{
    BaseURL: "https://api.apito.io/graphql",
    APIKey:  "invalid-key",
    Timeout: 5 * time.Second,
})

_, err := client.SearchResources(ctx, "users", nil, false)
if err != nil {
    if strings.Contains(err.Error(), "HTTP error 401") {
        fmt.Println("Authentication failed - check your API key")
    } else if strings.Contains(err.Error(), "HTTP error 403") {
        fmt.Println("Authorization failed - check your permissions")
    }
}

πŸ§ͺ Testing

Mock Client
// For testing, you can implement the interface
type MockClient struct{}

func (m *MockClient) SearchResources(ctx context.Context, model string, filter map[string]interface{}, aggregate bool) (*goapitosdk.SearchResult, error) {
    // Return mock data
    return &goapitosdk.SearchResult{
        Results: []*shared.DefaultDocumentStructure{
            {ID: "test-1", Data: map[string]interface{}{"name": "Test User"}},
        },
        Count: 1,
    }, nil
}

// Use in tests
func TestUserService(t *testing.T) {
    service := &UserService{apitoClient: &MockClient{}}
    // Test your service...
}

πŸ“ˆ Performance Tips

Connection Pooling
// Configure HTTP client for better performance
client := &http.Client{
    Transport: &http.Transport{
        MaxIdleConns:          100,
        MaxIdleConnsPerHost:   10,
        IdleConnTimeout:       90 * time.Second,
        TLSHandshakeTimeout:   10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    },
    Timeout: 30 * time.Second,
}

apitoClient := goapitosdk.NewClient(goapitosdk.Config{
    BaseURL:    "https://api.apito.io/graphql",
    APIKey:     "your-api-key",
    HTTPClient: client,
})
Batch Operations
// Instead of multiple individual requests, batch them
var wg sync.WaitGroup
results := make(chan *goapitosdk.SearchResult, 10)

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(page int) {
        defer wg.Done()
        filter := map[string]interface{}{"page": page, "limit": 100}
        result, err := client.SearchResources(ctx, "users", filter, false)
        if err == nil {
            results <- result
        }
    }(i)
}

go func() {
    wg.Wait()
    close(results)
}()

// Process results as they come in
for result := range results {
    // Process each batch...
}

πŸš€ Production Deployment

Environment Variables
# Required
APITO_BASE_URL=https://api.apito.io/graphql
APITO_API_KEY=your-production-api-key

# Optional
APITO_TENANT_ID=your-tenant-id
APITO_AUTH_TOKEN=your-auth-token
APITO_TIMEOUT=30s
Docker Configuration
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o app main.go

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
CMD ["./app"]
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apito-sdk-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: apito-sdk-app
  template:
    metadata:
      labels:
        app: apito-sdk-app
    spec:
      containers:
        - name: app
          image: your-app:latest
          env:
            - name: APITO_BASE_URL
              value: "https://api.apito.io/graphql"
            - name: APITO_API_KEY
              valueFrom:
                secretKeyRef:
                  name: apito-secrets
                  key: api-key

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup
git clone https://github.com/apito-io/go-internal-sdk.git
cd go-apito-sdk
go mod download
go test ./...

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ†˜ Support

Documentation ΒΆ

Index ΒΆ

Examples ΒΆ

Constants ΒΆ

View Source
const Version = "1.2.0"

Version represents the current version of the Go Apito SDK

Variables ΒΆ

This section is empty.

Functions ΒΆ

func CreateNewResourceTyped ΒΆ

func CreateNewResourceTyped[T any](c *Client, ctx context.Context, request *types.CreateAndUpdateRequest) (*types.TypedDocumentStructure[T], error)

CreateNewResourceTyped creates a new resource with typed result

func GetRelationDocumentsTyped ΒΆ

func GetRelationDocumentsTyped[T any](c *Client, ctx context.Context, _id string, connection map[string]interface{}) (*types.TypedSearchResult[T], error)

GetRelationDocumentsTyped retrieves related documents with typed results

func GetSingleResourceTyped ΒΆ

func GetSingleResourceTyped[T any](c *Client, ctx context.Context, model, _id string, singlePageData bool) (*types.TypedDocumentStructure[T], error)

GetSingleResourceTyped retrieves a single resource by model and ID with typed data

Example ΒΆ

ExampleTypedOperations shows how to use the typed operations in documentation

config := Config{
	BaseURL: BaseURL,
	APIKey:  APIKey,
	Timeout: 30 * time.Second,
}
client := NewClient(config)
ctx := context.Background()

// Get a single task with full type safety
task, err := GetSingleResourceTyped[Task](client, ctx, "task", "401fa9f2-b174-42b1-84da-1227be8d8755", false)
if err != nil {
	// Handle error appropriately
	return
}

// Access strongly typed fields
taskName := task.Data.Name
taskProgress := task.Data.Progress

_ = taskName
_ = taskProgress

func GetVersion ΒΆ

func GetVersion() string

GetVersion returns the current version of the SDK

func SearchResourcesTyped ΒΆ

func SearchResourcesTyped[T any](c *Client, ctx context.Context, model string, filter map[string]interface{}, aggregate bool) (*types.TypedSearchResult[T], error)

SearchResourcesTyped searches for resources with typed results

func UpdateResourceTyped ΒΆ

func UpdateResourceTyped[T any](c *Client, ctx context.Context, request *types.CreateAndUpdateRequest) (*types.TypedDocumentStructure[T], error)

UpdateResourceTyped updates a resource with typed result

Types ΒΆ

type Client ΒΆ

type Client struct {
	// contains filtered or unexported fields
}

Client represents the Apito SDK client

func NewClient ΒΆ

func NewClient(config Config) *Client

NewClient creates a new Apito SDK client

func (*Client) CreateNewResource ΒΆ

func (c *Client) CreateNewResource(ctx context.Context, request *types.CreateAndUpdateRequest) (*types.DefaultDocumentStructure, error)

CreateNewResource creates a new resource in the specified model with the given data and connections

func (*Client) Debug ΒΆ

func (c *Client) Debug(ctx context.Context, stage string, data ...interface{}) (interface{}, error)

Debug is used to debug the plugin, you can pass data here to debug the plugin

func (*Client) DeleteResource ΒΆ

func (c *Client) DeleteResource(ctx context.Context, model, _id string) error

DeleteResource deletes a resource by model and ID

func (*Client) GenerateTenantToken ΒΆ

func (c *Client) GenerateTenantToken(ctx context.Context, token string, tenantID string) (string, error)

GenerateTenantToken generates a new tenant token for the specified tenant ID

func (*Client) GetRelationDocuments ΒΆ

func (c *Client) GetRelationDocuments(ctx context.Context, _id string, connection map[string]interface{}) (*types.SearchResult, error)

GetRelationDocuments retrieves related documents for the given ID and connection parameters

func (*Client) GetSingleResource ΒΆ

func (c *Client) GetSingleResource(ctx context.Context, model, _id string, singlePageData bool) (*types.DefaultDocumentStructure, error)

GetSingleResource retrieves a single resource by model and ID, with optional single page data

func (*Client) SearchResources ΒΆ

func (c *Client) SearchResources(ctx context.Context, model string, filter map[string]interface{}, aggregate bool) (*types.SearchResult, error)

SearchResources searches for resources in the specified model using the provided filter

func (*Client) UpdateResource ΒΆ

UpdateResource updates an existing resource by model and ID, with optional single page data, data updates, and connection changes

type Config ΒΆ

type Config struct {
	BaseURL    string        // Base URL of the Apito GraphQL endpoint
	APIKey     string        // API key for authentication (X-APITO-KEY header)
	Timeout    time.Duration // HTTP client timeout (default: 30 seconds)
	HTTPClient *http.Client  // Custom HTTP client (optional)
}

Config represents the SDK configuration

Directories ΒΆ

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL