Skip to content

Response Handling

Understanding how to properly handle HTTP responses is crucial for building robust applications. This section covers response structure, status codes, headers, and error handling patterns.

Response Object Structure

All HTTP functions return a response object (map) with the following structure:

Response Object Structure
{
    "status": 200,                    // HTTP status code (integer)
    "statusText": "200 OK",           // Full status text (string)
    "body": "response content...",    // Response body (string)
    "headers": {                      // Headers map
        "Content-Type": "application/json",
        "Content-Length": "1234",
        "Cache-Control": "no-cache",
        "Set-Cookie": "session=abc123",
        // ... other headers
    }
}

Accessing Response Data

Status Information

Status Information
package main
import http
import fmt

var result = http.Get("https://api.example.com/data")
var response = result[0]
var err = result[1]

if err != None {
    fmt.Printf("Network Error: %s\n", err)
} else {
    // Access status code
    var statusCode = response["status"]
    var statusText = response["statusText"]

    fmt.Printf("Status: %d - %s\n", statusCode, statusText)

    // Check if request was successful
    if statusCode >= 200 and statusCode < 300 {
        fmt.Println("✅ Request successful!")
    } else if statusCode >= 400 and statusCode < 500 {
        fmt.Println("❌ Client error")
    } else if statusCode >= 500 {
        fmt.Println("💥 Server error")
    }
}

Response Body

Response Body
package main
import http
import json
import fmt

var result = http.Get("https://api.example.com/users/1")
var response = result[0]
var err = result[1]

if err != None {
    fmt.Printf("Error: %s\n", err)
} else if response["status"] == 200 {
    // Access response body
    var body = response["body"]

    // Parse JSON if content type is JSON
    var contentType = response["headers"]["Content-Type"]
    if contentType == "application/json" {
        var userData, parseErr = json.Unmarshal(body)
        if parseErr != None {
            fmt.Printf("JSON Parse Error: %s\n", parseErr)
        } else {
            fmt.Printf("User: %s\n", userData["name"])
        }
    } else {
        // Handle as plain text
        fmt.Printf("Response: %s\n", body)
    }
}

Response Headers

Response Headers
package main
import http
import fmt

var result = http.Get("https://api.example.com/data")
var response = result[0]
var err = result[1]

if err != None {
    fmt.Printf("Error: %s\n", err)
} else {
    var headers = response["headers"]

    // Access specific headers
    var contentType = headers["Content-Type"]
    var contentLength = headers["Content-Length"]
    var cacheControl = headers["Cache-Control"]
    var lastModified = headers["Last-Modified"]

    fmt.Printf("Content-Type: %s\n", contentType)
    fmt.Printf("Content-Length: %s\n", contentLength)
    fmt.Printf("Cache-Control: %s\n", cacheControl)
    fmt.Printf("Last-Modified: %s\n", lastModified)

    // Check for cookies
    var setCookie = headers["Set-Cookie"]
    if setCookie != None {
        fmt.Printf("Server set cookie: %s\n", setCookie)
    }
}

HTTP Status Codes

Success Codes (2xx)

Success Codes
package main
import http
import fmt

function handleSuccessResponse(response map) {
    var status = response["status"]

    match status {
        200 => fmt.Println("✅ OK - Request successful"),
        201 => fmt.Println("✅ Created - Resource created successfully"),
        202 => fmt.Println("✅ Accepted - Request accepted for processing"),
        204 => fmt.Println("✅ No Content - Success with no response body"),
        _ => fmt.Printf("✅ Success - Status: %d\n", status)
    }
}

Client Error Codes (4xx)

Client Error Codes
package main
import http
import fmt

function handleClientError(response map) {
    var status = response["status"]
    var body = response["body"]

    match status {
        400 => fmt.Printf("❌ Bad Request: %s\n", body),
        401 => fmt.Println("🔐 Unauthorized - Authentication required"),
        403 => fmt.Println("🚫 Forbidden - Access denied"),
        404 => fmt.Println("🔍 Not Found - Resource doesn't exist"),
        409 => fmt.Printf("⚠️  Conflict: %s\n", body),
        422 => fmt.Printf("📝 Unprocessable Entity: %s\n", body),
        429 => fmt.Println("⏱️  Too Many Requests - Rate limited"),
        _ => fmt.Printf("❌ Client Error %d: %s\n", status, body)
    }
}

Server Error Codes (5xx)

Server Error Codes
package main
import http
import fmt

function handleServerError(response map) {
    var status = response["status"]
    var body = response["body"]

    match status {
        500 => fmt.Printf("💥 Internal Server Error: %s\n", body),
        502 => fmt.Println("🌐 Bad Gateway - Upstream server error"),
        503 => fmt.Println("🚧 Service Unavailable - Server temporarily down"),
        504 => fmt.Println("⏰ Gateway Timeout - Upstream server timeout"),
        _ => fmt.Printf("💥 Server Error %d: %s\n", status, body)
    }
}

Content Type Handling

JSON Responses

JSON Responses
package main
import http
import json
import fmt

function handleJSONResponse(response map) {
    var contentType = response["headers"]["Content-Type"]

    // Check if response is JSON
    if contentType == "application/json" or contentType == "application/json; charset=utf-8" {
        var data, parseErr = json.Unmarshal(response["body"])
        if parseErr != None {
            fmt.Printf("JSON Parse Error: %s\n", parseErr)
            return None
        }
        return data
    } else {
        fmt.Printf("Expected JSON, got: %s\n", contentType)
        return None
    }
}

// Usage
var result = http.Get("https://api.example.com/users")
var response = result[0]
var err = result[1]

if err != None {
    fmt.Printf("Error: %s\n", err)
} else if response["status"] == 200 {
    var users = handleJSONResponse(response)
    if users != None {
        fmt.Printf("Found %d users\n", len(users))
    }
}

Text Responses

Text Responses
import http
import fmt

function handleTextResponse(response map) {
    var contentType = response["headers"]["Content-Type"]

    // Handle different text types
    match contentType {
        "text/plain" => {
            fmt.Println("Plain text response:")
            fmt.Println(response["body"])
        },
        "text/html" => {
            fmt.Println("HTML response received")
            // Could parse HTML here
        },
        "text/csv" => {
            fmt.Println("CSV data received:")
            // Could parse CSV here
        },
        _ => {
            fmt.Printf("Text response (%s):\n", contentType)
            fmt.Println(response["body"])
        }
    }
}

Binary Responses

Binary Responses
import http
import fmt

function handleBinaryResponse(response map) {
    var contentType = response["headers"]["Content-Type"]
    var contentLength = response["headers"]["Content-Length"]

    match contentType {
        "image/jpeg", "image/png", "image/gif" => {
            fmt.Printf("Image received: %s bytes\n", contentLength)
            // Could save image data here
        },
        "application/pdf" => {
            fmt.Printf("PDF received: %s bytes\n", contentLength)
            // Could save PDF data here
        },
        "application/zip" => {
            fmt.Printf("ZIP file received: %s bytes\n", contentLength)
            // Could save ZIP data here
        },
        _ => {
            fmt.Printf("Binary data received (%s): %s bytes\n", contentType, contentLength)
        }
    }
}

Error Handling Patterns

Comprehensive Error Handling

Comprehensive Error Handling
import http
import json
import fmt

function robustAPICall(url string) {
    var result = http.Get(url)
    var response = result[0]
    var err = result[1]

    // Handle network errors
    if err != None {
        fmt.Printf("❌ Network Error: %s\n", err)
        return None, "network_error"
    }

    var status = response["status"]

    // Handle different status code ranges
    if status >= 200 and status < 300 {
        // Success - process response
        return response, "success"
    } else if status >= 300 and status < 400 {
        // Redirection - could handle automatically
        fmt.Printf("🔄 Redirect: %s\n", response["statusText"])
        return response, "redirect"
    } else if status >= 400 and status < 500 {
        // Client error - usually don't retry
        fmt.Printf("❌ Client Error %d: %s\n", status, response["body"])
        return response, "client_error"
    } else if status >= 500 {
        // Server error - might retry
        fmt.Printf("💥 Server Error %d: %s\n", status, response["body"])
        return response, "server_error"
    } else {
        // Unknown status
        fmt.Printf("❓ Unknown Status %d: %s\n", status, response["statusText"])
        return response, "unknown_error"
    }
}

// Usage with error handling
var response, errorType = robustAPICall("https://api.example.com/data")
match errorType {
    "success" => fmt.Println("✅ API call successful"),
    "network_error" => fmt.Println("🌐 Check network connection"),
    "client_error" => fmt.Println("📝 Fix request parameters"),
    "server_error" => fmt.Println("⏳ Retry later"),
    _ => fmt.Println("❓ Unknown issue occurred")
}

Retry Logic with Exponential Backoff

Retry Logic
import http
import fmt

function apiCallWithRetry(url string, maxRetries int) {
    var attempt = 0

    for attempt < maxRetries {
        attempt = attempt + 1

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

        // Network error - retry
        if err != None {
            fmt.Printf("Attempt %d failed: %s\n", attempt, err)
            if attempt < maxRetries {
                fmt.Printf("Retrying in %d seconds...\n", attempt * 2)
                // In real implementation, add delay here
            }
            continue
        }

        var status = response["status"]

        // Success - return response
        if status >= 200 and status < 300 {
            fmt.Printf("✅ Success on attempt %d\n", attempt)
            return response, None
        }

        // Server error - retry
        if status >= 500 {
            fmt.Printf("Server error (attempt %d): %d\n", attempt, status)
            if attempt < maxRetries {
                fmt.Printf("Retrying server error...\n")
            }
            continue
        }

        // Client error - don't retry
        if status >= 400 and status < 500 {
            fmt.Printf("❌ Client error: %d - %s\n", status, response["statusText"])
            return response, "Client error - not retrying"
        }
    }

    return None, "All retry attempts failed"
}

// Usage
var response, retryErr = apiCallWithRetry("https://unreliable-api.example.com", 3)
if retryErr != None {
    fmt.Printf("Final Error: %s\n", retryErr)
} else {
    fmt.Printf("Success: %s\n", response["body"])
}

Response Validation

Content Validation

Content Validation
import http
import json
import fmt

function validateAPIResponse(response map) {
    var status = response["status"]
    var headers = response["headers"]
    var body = response["body"]

    // Check status code
    if status != 200 {
        return "Invalid status code: " + status
    }

    // Check content type
    var contentType = headers["Content-Type"]
    if contentType != "application/json" {
        return "Expected JSON, got: " + contentType
    }

    // Check if body is valid JSON
    var data, parseErr = json.Unmarshal(body)
    if parseErr != None {
        return "Invalid JSON: " + parseErr
    }

    // Check required fields (example)
    if data["id"] == None {
        return "Missing required field: id"
    }

    if data["name"] == None {
        return "Missing required field: name"
    }

    return None  // Valid response
}

// Usage
var result = http.Get("https://api.example.com/user/123")
var response = result[0]
var err = result[1]

if err != None {
    fmt.Printf("Network Error: %s\n", err)
} else {
    var validationErr = validateAPIResponse(response)
    if validationErr != None {
        fmt.Printf("Validation Error: %s\n", validationErr)
    } else {
        fmt.Println("✅ Response is valid")
        var userData, _ = json.Unmarshal(response["body"])
        fmt.Printf("User: %s (ID: %s)\n", userData["name"], userData["id"])
    }
}

Response Size Limits

Response Size Limits
import http
import fmt

function checkResponseSize(response map, maxSize int) {
    var contentLength = response["headers"]["Content-Length"]

    if contentLength != None {
        // Convert string to int (simplified)
        // In real implementation, use cast.ToInt()
        fmt.Printf("Response size: %s bytes\n", contentLength)

        // Check if response is too large
        // This is a simplified check
        if len(response["body"]) > maxSize {
            return "Response too large"
        }
    }

    return None
}

// Usage
var result = http.Get("https://api.example.com/large-data")
var response = result[0]
var err = result[1]

if err != None {
    fmt.Printf("Error: %s\n", err)
} else {
    var sizeErr = checkResponseSize(response, 1000000)  // 1MB limit
    if sizeErr != None {
        fmt.Printf("Size Error: %s\n", sizeErr)
    } else {
        fmt.Println("✅ Response size acceptable")
    }
}

Best Practices

1. Always Check Status Codes

Check Status Codes
1
2
3
4
5
if response["status"] >= 200 and response["status"] < 300 {
    // Success - process response
} else {
    // Error - handle appropriately
}

2. Validate Content Type

Validate Content Type
1
2
3
4
5
var expectedType = "application/json"
var actualType = response["headers"]["Content-Type"]
if actualType != expectedType {
    fmt.Printf("Expected %s, got %s\n", expectedType, actualType)
}

3. Handle Empty Responses

Handle Empty Responses
1
2
3
4
5
6
var body = response["body"]
if body == "" or body == None {
    fmt.Println("Empty response body")
} else {
    // Process body
}

4. Log Response Details for Debugging

Log Response Details
1
2
3
fmt.Printf("Status: %d\n", response["status"])
fmt.Printf("Headers: %s\n", response["headers"])
fmt.Printf("Body length: %d\n", len(response["body"]))

5. Use Pattern Matching for Status Handling

Pattern Matching Status
1
2
3
4
5
6
7
var status = response["status"]
match status {
    200 => handleSuccess(response),
    404 => handleNotFound(response),
    500 => handleServerError(response),
    _ => handleOtherStatus(response, status)
}

Next Steps