HTTP client in Go: making requests correctly

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why HTTP Client in Go Deserves Attention

Modern web applications rarely work in isolation. Almost every service interacts with external APIs, microservices, or third-party resources via HTTP. The Go language (Golang) provides a powerful built-in library net/http that allows you to create efficient and high-performance HTTP clients without third-party dependencies.

In this article, we will break down how to properly work with the HTTP client in Go: from simple GET requests to error handling and timeout management. You will learn how to avoid common mistakes and write reliable code.



Basics of Working with HTTP Client in Go

The net/http library in Go is designed with performance in mind. Unlike many other languages where each request creates a new connection, Go uses a connection pool by default. This means TCP connections are reused, which significantly speeds up operations.



Simple GET Request

Let's start with the simplest example — sending a GET request using the http.Get() function:



package main

import ( "fmt" "io" "net/http" "os")

func main() { // Simple GET request resp, err := http.Get("https://api.github.com") if err != nil { fmt.Printf("Error executing request: %v", err) os.Exit(1) } defer resp.Body.Close()

// Read response body body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Error reading response: %v", err) os.Exit(1) }

fmt.Printf("Status: %s", resp.Status) fmt.Printf("Response body: %s", string(body))}


Important: always close the response body (resp.Body.Close()). Use defer for guaranteed closure, even if an error occurs.



GET Request with Parameters and Headers

For more complex requests, it's better to use the full syntax by creating an http.Request object:



package main

import ( "fmt" "io" "net/http" "time")

func main() { // Create a new client client := &http.Client{ Timeout: 10 * time.Second, }

// Create a request req, err := http.NewRequest("GET", "https://api.example.com/users", nil) if err != nil { fmt.Printf("Error creating request: %v", err) return }

// Add headers req.Header.Set("Authorization", "Bearer your-token-here") req.Header.Set("Accept", "application/json") req.Header.Set("User-Agent", "Go-http-client/1.0")

// Add query parameters q := req.URL.Query() q.Add("limit", "10") q.Add("offset", "0") req.URL.RawQuery = q.Encode()

// Execute the request resp, err := client.Do(req) if err != nil { fmt.Printf("Error executing request: %v", err) return } defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body) fmt.Printf("Response: %s", string(body))}


Working with POST Requests and JSON

POST requests with JSON body are a standard task when working with REST APIs. Go provides convenient tools for data serialization.



Sending JSON via POST

package main

import ( "bytes" "encoding/json" "fmt" "net/http" "time")

type User struct { Name string `json:"name"` Email string `json:"email"` Age int `json:"age"`}

func main() { user := User{ Name: "Ivan Petrov", Email: "ivan@example.com", Age: 30, }

// Serialize the struct to JSON jsonData, err := json.Marshal(user) if err != nil { fmt.Printf("JSON serialization error: %v", err) return }

client := &http.Client{Timeout: 5 * time.Second}

Blogs

Book Recommendations