HTTP & Web Requests in Go

Building web servers and making HTTP requests

🌐 What is HTTP in Go?

Go's net/http package provides comprehensive tools for building web servers and making HTTP requests. Create REST APIs, web applications, and HTTP clients with ease and efficiency.


// Simple HTTP server example
package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
                                    

Output:

Server running on http://localhost:8080
Response: Hello, World!

HTTP Operations in Go

🖥️

HTTP Server

Create web servers and APIs

http.ListenAndServe(":8080", nil)
📡

HTTP Client

Make requests to web services

resp, err := http.Get(url)
🛣️

Routing

Handle different URL paths

http.HandleFunc("/api", handler)
📋

Middleware

Add functionality to requests

http.Handle("/", middleware(handler))

🔹 Creating HTTP Server

Build a simple web server with multiple routes:

package main

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

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Welcome to Go HTTP Server!")
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    users := []User{
        {ID: 1, Name: "Alice"},
        {ID: 2, Name: "Bob"},
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}

func main() {
    http.HandleFunc("/", homeHandler)
    http.HandleFunc("/users", usersHandler)
    
    fmt.Println("Server starting on :8080")
    http.ListenAndServe(":8080", nil)
}

Output:

Server starting on :8080
GET / → Welcome to Go HTTP Server!
GET /users → [{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]

🔹 Making HTTP Requests

Send HTTP requests to external APIs:

package main

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

func main() {
    // GET request
    resp, err := http.Get("https://jsonplaceholder.typicode.com/posts/1")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println("GET Response:")
    fmt.Println(string(body))

    // POST request
    jsonData := `{"title":"Go HTTP","body":"Learning HTTP requests","userId":1}`
    resp, err = http.Post(
        "https://jsonplaceholder.typicode.com/posts",
        "application/json",
        strings.NewReader(jsonData),
    )
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("POST Status:", resp.Status)
}

Output:

GET Response:
{"userId":1,"id":1,"title":"sunt aut facere...","body":"quia et suscipit..."}
POST Status: 201 Created

🔹 HTTP Client with Custom Configuration

Create custom HTTP clients with timeouts and headers:

package main

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

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

    // Create request with custom headers
    req, err := http.NewRequest("GET", "https://api.github.com/users/golang", nil)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    req.Header.Set("User-Agent", "Go-HTTP-Client/1.0")
    req.Header.Set("Accept", "application/json")

    // Send request
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("Status:", resp.Status)
    fmt.Println("Headers:", resp.Header.Get("Content-Type"))

    body, _ := io.ReadAll(resp.Body)
    fmt.Println("Response length:", len(body), "bytes")
}

Output:

Status: 200 OK
Headers: application/json; charset=utf-8
Response length: 1234 bytes

🔹 REST API Example

Build a simple REST API with CRUD operations:

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
    "strings"
)

type Task struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
    Done bool   `json:"done"`
}

var tasks = []Task{
    {ID: 1, Name: "Learn Go", Done: false},
    {ID: 2, Name: "Build API", Done: true},
}

func tasksHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    
    switch r.Method {
    case "GET":
        json.NewEncoder(w).Encode(tasks)
    case "POST":
        var newTask Task
        json.NewDecoder(r.Body).Decode(&newTask)
        newTask.ID = len(tasks) + 1
        tasks = append(tasks, newTask)
        w.WriteHeader(http.StatusCreated)
        json.NewEncoder(w).Encode(newTask)
    default:
        w.WriteHeader(http.StatusMethodNotAllowed)
    }
}

func taskHandler(w http.ResponseWriter, r *http.Request) {
    idStr := strings.TrimPrefix(r.URL.Path, "/tasks/")
    id, _ := strconv.Atoi(idStr)
    
    for i, task := range tasks {
        if task.ID == id {
            if r.Method == "DELETE" {
                tasks = append(tasks[:i], tasks[i+1:]...)
                w.WriteHeader(http.StatusNoContent)
                return
            }
        }
    }
    w.WriteHeader(http.StatusNotFound)
}

func main() {
    http.HandleFunc("/tasks", tasksHandler)
    http.HandleFunc("/tasks/", taskHandler)
    
    fmt.Println("REST API server running on :8080")
    http.ListenAndServe(":8080", nil)
}

Output:

REST API server running on :8080
GET /tasks → List all tasks
POST /tasks → Create new task
DELETE /tasks/1 → Delete task with ID 1

🧠 Test Your Knowledge

Which function starts an HTTP server in Go?