Skip to content

Examples & Patterns

This section provides real-world examples and common patterns for using the HTTP module effectively in production applications.

Complete API Client Example

Complete API Client
package main
import http
import json
import fmt

// Complete API client for a REST service
type APIClient struct {
    baseUrl string
    token string
    userAgent string
}

function newAPIClient(baseUrl string, token string) {
    return {
        "baseUrl": baseUrl,
        "token": token,
        "userAgent": "HarneetApp/1.0"
    }
}

function apiRequest(client map, method string, endpoint string, data map) {
    var url = client["baseUrl"] + endpoint

    var body = ""
    if data != None {
        var jsonData, _ = json.Marshal(data)
        body = jsonData
    }

    var request = http.NewRequest(method, url, body)[0]

    // Standard headers
    request = http.SetHeader(request, "Content-Type", "application/json")[0]
    request = http.SetHeader(request, "Accept", "application/json")[0]
    request = http.SetHeader(request, "User-Agent", client["userAgent"])[0]

    // Authentication
    if client["token"] != "" {
        request = http.SetHeader(request, "Authorization", "Bearer " + client["token"])[0]
    }

    var result = http.Do(request)
    var response = result[0]
    var err = result[1]

    if err != None {
        return None, "Network error: " + err
    }

    if response["status"] >= 200 and response["status"] < 300 {
        var responseData, parseErr = json.Unmarshal(response["body"])
        if parseErr != None {
            return None, "JSON parse error: " + parseErr
        }
        return responseData, None
    } else {
        return None, "HTTP error " + response["status"] + ": " + response["statusText"]
    }
}

// Usage example
var client = newAPIClient("https://api.example.com", "your-token-here")

// Get users
var users, getUsersErr = apiRequest(client, "GET", "/users", None)
if getUsersErr != None {
    fmt.Printf("Get users failed: %s\n", getUsersErr)
} else {
    fmt.Printf("Found %d users\n", len(users))
}

// Create user
var newUserData = {"name": "Alice", "email": "alice@example.com"}
var createdUser, createErr = apiRequest(client, "POST", "/users", newUserData)
if createErr != None {
    fmt.Printf("Create user failed: %s\n", createErr)
} else {
    fmt.Printf("Created user: %s\n", createdUser["name"])
}

Retry Logic with Exponential Backoff

Exponential Backoff
package main
import http
import fmt

function requestWithRetry(request map, maxRetries int) {
    var attempt = 0
    var delay = 1  // Start with 1 second delay

    for attempt < maxRetries {
        attempt = attempt + 1

        var result = http.Do(request)
        var response = result[0]
        var err = result[1]

        if err != None {
            fmt.Printf("Attempt %d failed: %s\n", attempt, err)
            if attempt < maxRetries {
                fmt.Printf("Retrying in %d seconds...\n", delay)
                // In real implementation, add sleep here
                delay = delay * 2  // Exponential backoff
            }
        } else if response["status"] >= 200 and response["status"] < 300 {
            fmt.Printf("✅ Request succeeded on attempt %d\n", attempt)
            return response, None
        } else if response["status"] >= 500 {
            fmt.Printf("Server error (attempt %d): %d - %s\n", attempt, response["status"], response["statusText"])
            if attempt < maxRetries {
                fmt.Printf("Retrying server error in %d seconds...\n", delay)
                delay = delay * 2
            }
        } else {
            fmt.Printf("❌ Client error: %d - %s\n", response["status"], response["statusText"])
            return response, "Client error - not retrying"
        }
    }

    return None, "All retry attempts failed"
}

// Usage
var request = http.NewRequest("GET", "https://unreliable-api.example.com/data", "")[0]
var authRequest = http.SetHeader(request, "Authorization", "Bearer token123")[0]
var response, retryErr = requestWithRetry(authRequest, 3)

if retryErr != None {
    fmt.Printf("Final Error: %s\n", retryErr)
} else {
    fmt.Printf("Success: %s\n", response["body"])
}

Parallel API Requests

Parallel Requests
package main
import http
import fmt

// Make multiple API calls in sequence (simulated parallel)
function parallelAPIRequests() {
    var endpoints = [
        {"path": "/users", "name": "Users"},
        {"path": "/posts", "name": "Posts"},
        {"path": "/comments", "name": "Comments"}
    ]
    var baseUrl = "https://jsonplaceholder.typicode.com"

    var results = []

    fmt.Println("Making parallel API requests...")

    for endpoint in endpoints {
        var url = baseUrl + endpoint["path"]
        var request = http.NewRequest("GET", url, "")[0]
        var userAgentRequest = http.SetHeader(request, "User-Agent", "HarneetApp/1.0")[0]

        var result = http.Do(userAgentRequest)
        var response = result[0]
        var err = result[1]

        var requestResult = {
            "endpoint": endpoint["name"],
            "success": false,
            "status": 0,
            "error": None
        }

        if err != None {
            requestResult["error"] = err
            fmt.Printf("❌ %s failed: %s\n", endpoint["name"], err)
        } else {
            requestResult["success"] = response["status"] >= 200 and response["status"] < 300
            requestResult["status"] = response["status"]

            if requestResult["success"] {
                fmt.Printf("✅ %s: Status %d\n", endpoint["name"], response["status"])
            } else {
                fmt.Printf("❌ %s: Status %d\n", endpoint["name"], response["status"])
            }
        }

        results = append(results, requestResult)
    }

    // Summary
    var successCount = 0
    for result in results {
        if result["success"] {
            successCount = successCount + 1
        }
    }

    fmt.Printf("\nSummary: %d/%d requests successful\n", successCount, len(results))
    return results
}

// Execute parallel requests
var results = parallelAPIRequests()

Request/Response Logging

Request Logging
package main
import http
import json
import fmt

// Detailed logging for debugging
function loggedAPICall(method string, url string, body string, headers map) {
    fmt.Printf("🔄 Making %s request to %s\n", method, url)

    // Create request
    var request = http.NewRequest(method, url, body)[0]

    // Add headers
    for key, value in headers {
        request = http.SetHeader(request, key, value)[0]
    }

    // Log request details
    fmt.Printf("📤 Request Details:\n")
    fmt.Printf("   Method: %s\n", method)
    fmt.Printf("   URL: %s\n", url)
    fmt.Printf("   Body: %s\n", body)
    fmt.Printf("   Headers:\n")
    var requestHeaders = request["headers"]
    for key, value in requestHeaders {
        fmt.Printf("     %s: %s\n", key, value)
    }

    // Execute request
    var result = http.Do(request)
    var response = result[0]
    var err = result[1]

    if err != None {
        fmt.Printf("❌ Request failed: %s\n", err)
        return None
    }

    // Log response details
    fmt.Printf("📥 Response Details:\n")
    fmt.Printf("   Status: %d - %s\n", response["status"], response["statusText"])
    fmt.Printf("   Headers:\n")
    var responseHeaders = response["headers"]
    for key, value in responseHeaders {
        fmt.Printf("     %s: %s\n", key, value)
    }
    fmt.Printf("   Body: %s\n", response["body"])

    return response
}

// Usage
var headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer token123",
    "X-API-Version": "v1"
}

var requestBody = "{\"action\": \"test\"}"
var response = loggedAPICall("POST", "https://httpbin.org/post", requestBody, headers)

File Upload Simulation

File Upload
package main
import http
import fmt

// Simulate file upload with multipart form data
function uploadFile(url string, filename string, content string, token string) {
    // Create multipart form data (simplified)
    var boundary = "----HarneetFormBoundary7MA4YWxkTrZu0gW"
    var formData = "--" + boundary + "\r\n"
    formData = formData + "Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n"
    formData = formData + "Content-Type: text/plain\r\n\r\n"
    formData = formData + content + "\r\n"
    formData = formData + "--" + boundary + "--\r\n"

    var request = http.NewRequest("POST", url, formData)[0]

    // Set multipart content type
    var contentType = "multipart/form-data; boundary=" + boundary
    request = http.SetHeader(request, "Content-Type", contentType)[0]

    // Add authentication
    if token != "" {
        request = http.SetHeader(request, "Authorization", "Bearer " + token)[0]
    }

    var result = http.Do(request)
    var response = result[0]
    var err = result[1]

    if err != None {
        return "Upload failed: " + err
    } else if response["status"] >= 200 and response["status"] < 300 {
        fmt.Printf("✅ File uploaded successfully: %s\n", filename)
        return None
    } else {
        return "Upload failed with status: " + response["statusText"]
    }
}

// Usage
var uploadErr = uploadFile(
    "https://httpbin.org/post",
    "test.txt",
    "This is the file content",
    "token123"
)

if uploadErr != None {
    fmt.Printf("Upload Error: %s\n", uploadErr)
}

API Rate Limiting Handler

Rate Limiting
package main
import http
import fmt

// Handle API rate limiting with automatic retry
function rateLimitedRequest(request map) {
    var maxRetries = 5
    var attempt = 0

    for attempt < maxRetries {
        attempt = attempt + 1

        var result = http.Do(request)
        var response = result[0]
        var err = result[1]

        if err != None {
            fmt.Printf("Network error: %s\n", err)
            return None, err
        }

        var status = response["status"]

        if status == 429 {
            // Rate limited
            var retryAfter = response["headers"]["Retry-After"]
            if retryAfter != None {
                fmt.Printf("Rate limited. Retry after: %s seconds\n", retryAfter)
            } else {
                fmt.Printf("Rate limited. Waiting before retry...\n")
            }

            if attempt < maxRetries {
                // In real implementation, wait for the specified time
                fmt.Printf("Retrying in attempt %d...\n", attempt + 1)
            }
        } else if status >= 200 and status < 300 {
            fmt.Printf("✅ Request successful after %d attempts\n", attempt)
            return response, None
        } else {
            fmt.Printf("❌ Request failed with status: %d\n", status)
            return response, "HTTP error: " + response["statusText"]
        }
    }

    return None, "Rate limit retries exhausted"
}

// Usage
var request = http.NewRequest("GET", "https://api.example.com/data", "")[0]
var authRequest = http.SetHeader(request, "Authorization", "Bearer token123")[0]
var response, rateLimitErr = rateLimitedRequest(authRequest)

if rateLimitErr != None {
    fmt.Printf("Rate Limit Error: %s\n", rateLimitErr)
} else {
    fmt.Printf("Success: %s\n", response["body"])
}

Configuration-Driven API Client

Config-Driven Client
package main
import http
import json
import fmt

// API client with configuration
type APIConfig struct {
    baseUrl string
    timeout int
    retries int
    headers map
}

function createAPIConfig(baseUrl string) {
    return {
        "baseUrl": baseUrl,
        "timeout": 30,
        "retries": 3,
        "headers": {
            "User-Agent": "HarneetApp/1.0",
            "Accept": "application/json"
        }
    }
}

function configuredRequest(config map, method string, endpoint string, data map, authToken string) {
    var url = config["baseUrl"] + endpoint

    var body = ""
    if data != None {
        var jsonData, _ = json.Marshal(data)
        body = jsonData
    }

    var request = http.NewRequest(method, url, body)[0]

    // Apply default headers from config
    var defaultHeaders = config["headers"]
    for key, value in defaultHeaders {
        request = http.SetHeader(request, key, value)[0]
    }

    // Add content type for POST/PUT
    if method == "POST" or method == "PUT" or method == "PATCH" {
        request = http.SetHeader(request, "Content-Type", "application/json")[0]
    }

    // Add authentication
    if authToken != "" {
        request = http.SetHeader(request, "Authorization", "Bearer " + authToken)[0]
    }

    // Execute with retry logic
    var maxRetries = config["retries"]
    var attempt = 0

    for attempt < maxRetries {
        attempt = attempt + 1

        var result = http.Do(request)
        var response = result[0]
        var err = result[1]

        if err != None {
            if attempt < maxRetries {
                fmt.Printf("Attempt %d failed, retrying...\n", attempt)
                continue
            }
            return None, "Network error after " + attempt + " attempts: " + err
        }

        if response["status"] >= 200 and response["status"] < 300 {
            var responseData, parseErr = json.Unmarshal(response["body"])
            if parseErr != None {
                return None, "JSON parse error: " + parseErr
            }
            return responseData, None
        } else if response["status"] >= 500 and attempt < maxRetries {
            fmt.Printf("Server error (attempt %d), retrying...\n", attempt)
            continue
        } else {
            return None, "HTTP error " + response["status"] + ": " + response["statusText"]
        }
    }

    return None, "All retry attempts failed"
}

// Usage
var config = createAPIConfig("https://api.example.com")
var token = "your-auth-token"

// Get data
var userData, getUserErr = configuredRequest(config, "GET", "/users/123", None, token)
if getUserErr != None {
    fmt.Printf("Get user failed: %s\n", getUserErr)
} else {
    fmt.Printf("User: %s\n", userData["name"])
}

// Create data
var newUser = {"name": "Alice", "email": "alice@example.com"}
var createdUser, createErr = configuredRequest(config, "POST", "/users", newUser, token)
if createErr != None {
    fmt.Printf("Create user failed: %s\n", createErr)
} else {
    fmt.Printf("Created user ID: %s\n", createdUser["id"])
}

Health Check and Service Discovery

Health Check
package main
import http
import fmt

// Service health checker
function checkServiceHealth(services array) {
    var healthResults = []

    for service in services {
        var serviceName = service["name"]
        var healthUrl = service["url"] + "/health"

        fmt.Printf("Checking %s...\n", serviceName)

        var result = http.Get(healthUrl)
        var response = result[0]
        var err = result[1]

        var healthStatus = {
            "service": serviceName,
            "url": healthUrl,
            "healthy": false,
            "status": 0,
            "responseTime": 0,
            "error": None
        }

        if err != None {
            healthStatus["error"] = err
            fmt.Printf("❌ %s: %s\n", serviceName, err)
        } else {
            healthStatus["status"] = response["status"]
            healthStatus["healthy"] = response["status"] == 200

            if healthStatus["healthy"] {
                fmt.Printf("✅ %s: Healthy (Status: %d)\n", serviceName, response["status"])
            } else {
                fmt.Printf("⚠️  %s: Unhealthy (Status: %d)\n", serviceName, response["status"])
            }
        }

        healthResults = append(healthResults, healthStatus)
    }

    return healthResults
}

// Usage
var services = [
    {"name": "User Service", "url": "https://user-api.example.com"},
    {"name": "Order Service", "url": "https://order-api.example.com"},
    {"name": "Payment Service", "url": "https://payment-api.example.com"}
]

var healthResults = checkServiceHealth(services)

// Summary
var healthyCount = 0
for result in healthResults {
    if result["healthy"] {
        healthyCount = healthyCount + 1
    }
}

fmt.Printf("\nHealth Check Summary: %d/%d services healthy\n", healthyCount, len(healthResults))

Best Practices Summary

1. Error Handling

  • Always check for network errors first
  • Handle different HTTP status code ranges appropriately
  • Use retry logic for transient failures
  • Don't retry client errors (4xx)

2. Authentication

  • Use Bearer tokens when possible
  • Store tokens securely
  • Handle token expiration gracefully
  • Use appropriate authentication headers

3. Request Building

  • Set appropriate Content-Type headers
  • Include User-Agent for identification
  • Use request IDs for tracing
  • Set reasonable timeouts

4. Response Processing

  • Validate content types
  • Parse JSON safely with error handling
  • Check response sizes for large responses
  • Log responses for debugging

5. Performance

  • Reuse connections when possible
  • Implement proper retry logic
  • Use appropriate timeouts
  • Consider rate limiting

6. Monitoring

  • Log request/response details
  • Track success/failure rates
  • Monitor response times
  • Implement health checks

These patterns provide a solid foundation for building robust HTTP clients in Harneet applications.