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 |
|---|
| 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 |
|---|
| 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 |
|---|
| if response["status"] >= 200 and response["status"] < 300 {
// Success - process response
} else {
// Error - handle appropriately
}
|
2. Validate Content Type
| Validate Content Type |
|---|
| 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 |
|---|
| 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 |
|---|
| 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 |
|---|
| var status = response["status"]
match status {
200 => handleSuccess(response),
404 => handleNotFound(response),
500 => handleServerError(response),
_ => handleOtherStatus(response, status)
}
|
Next Steps