HTTP

Back

Loading concept...

๐ŸŒ Go HTTP: Your Gateway to the Web World

Analogy: Think of HTTP like a postal service for the internet. When you send a letter, you write it, put it in an envelope with addresses, add stamps (headers), and the post office delivers it. The recipient reads it and sends a reply back. Thatโ€™s exactly how HTTP works between computers!


๐Ÿ“ฌ HTTP Client Operations: Sending Letters to the Internet

Imagine you want to send a letter to a friend (a server). In Go, the net/http package is your postal service counter!

The Simple Way: Just Send It!

package main

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

func main() {
    // Ask for something (GET request)
    resp, err := http.Get("https://api.example.com/hello")
    if err != nil {
        fmt.Println("Oops! Letter lost:", err)
        return
    }
    defer resp.Body.Close()

    // Read the reply
    body, _ := io.ReadAll(resp.Body)
    fmt.Println("Reply:", string(body))
}

Sending Data: POST is Like Mailing a Package

import (
    "bytes"
    "net/http"
)

func sendPackage() {
    // Your package content
    data := []byte(`{"name": "Gopher", "age": 10}`)

    // Send the package
    resp, err := http.Post(
        "https://api.example.com/users",
        "application/json",
        bytes.NewBuffer(data),
    )
    if err != nil {
        return
    }
    defer resp.Body.Close()
}

Custom Requests: The VIP Letter Service

Sometimes you need more control, like choosing express delivery!

func customRequest() {
    client := &http.Client{}

    req, _ := http.NewRequest(
        "PUT",
        "https://api.example.com/update",
        bytes.NewBuffer([]byte(`{"status":"active"}`)),
    )

    resp, _ := client.Do(req)
    defer resp.Body.Close()
}

๐Ÿ“ HTTP Headers and Cookies: The Envelope Details

Headers are like special instructions written ON the envelope. Cookies are like membership cards you show every time!

Adding Headers: Writing Special Instructions

func requestWithHeaders() {
    client := &http.Client{}
    req, _ := http.NewRequest("GET",
        "https://api.example.com/secret", nil)

    // Add special instructions
    req.Header.Set("Authorization", "Bearer my-token")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Add("Accept-Language", "en-US")

    resp, _ := client.Do(req)
    defer resp.Body.Close()

    // Read server's headers
    serverType := resp.Header.Get("Server")
    fmt.Println("Server:", serverType)
}

Cookies: Your Internet Membership Card

func handleCookies() {
    // Create a cookie jar to store cookies
    jar, _ := cookiejar.New(nil)
    client := &http.Client{Jar: jar}

    // First visit - server gives you a cookie
    client.Get("https://shop.example.com/login")

    // Next visit - cookie sent automatically!
    client.Get("https://shop.example.com/cart")

    // Manual cookie creation
    cookie := &http.Cookie{
        Name:  "session_id",
        Value: "abc123",
    }
    req, _ := http.NewRequest("GET",
        "https://shop.example.com", nil)
    req.AddCookie(cookie)
}

๐Ÿ” URL Query Parameters: Questions in the Address

Query parameters are like adding specific questions to your letterโ€™s address: โ€œ123 Main St, apt 4B, floor 2โ€

graph TD A["Base URL"] --> B["?"] B --> C["key1=value1"] C --> D["&"] D --> E["key2=value2"] F["Result: url.com?key1=value1&key2=value2"]

Building URLs with Questions

import "net/url"

func buildURL() {
    baseURL := "https://api.example.com/search"

    // Create URL with questions
    params := url.Values{}
    params.Add("query", "golang")
    params.Add("page", "1")
    params.Add("sort", "recent")

    fullURL := baseURL + "?" + params.Encode()
    // Result: https://api.example.com/search?
    //         query=golang&page=1&sort=recent

    fmt.Println(fullURL)
}

Reading Query Parameters

func parseQuery() {
    rawURL := "https://example.com/search?name=Go&version=1.21"

    parsed, _ := url.Parse(rawURL)

    // Get all questions and answers
    queries := parsed.Query()

    name := queries.Get("name")       // "Go"
    version := queries.Get("version") // "1.21"
}

๐Ÿ“ฆ net/url Package: Your Address Parser

The net/url package is like a smart address reader. It breaks down any web address into understandable parts!

graph TD A["Full URL"] --> B["Scheme: https"] A --> C["Host: example.com"] A --> D["Path: /api/users"] A --> E["Query: id=123"] A --> F["Fragment: section1"]

Breaking Down an Address

import "net/url"

func parseAddress() {
    rawURL := "https://user:pass@example.com:8080/path?q=1#top"

    u, _ := url.Parse(rawURL)

    fmt.Println("Scheme:", u.Scheme)   // https
    fmt.Println("Host:", u.Host)       // example.com:8080
    fmt.Println("Path:", u.Path)       // /path
    fmt.Println("Query:", u.RawQuery)  // q=1
    fmt.Println("Fragment:", u.Fragment) // top
    fmt.Println("User:", u.User.Username()) // user
}

Building Addresses Safely

func buildSafeURL() {
    u := &url.URL{
        Scheme: "https",
        Host:   "api.example.com",
        Path:   "/users/search",
    }

    q := u.Query()
    q.Set("name", "John Doe")  // Spaces handled!
    q.Set("city", "New York")
    u.RawQuery = q.Encode()

    fmt.Println(u.String())
    // https://api.example.com/users/search?
    // city=New+York&name=John+Doe
}

๐Ÿ  HTTP Server Basics: Building Your Own Post Office

Now YOU become the post office! You receive letters and send replies.

The Simplest Server

package main

import (
    "fmt"
    "net/http"
)

func main() {
    // When someone knocks on /hello door
    http.HandleFunc("/hello", func(w http.ResponseWriter,
        r *http.Request) {
        fmt.Fprintf(w, "Hello, visitor!")
    })

    // Open the post office on port 8080
    fmt.Println("Server starting on :8080")
    http.ListenAndServe(":8080", nil)
}

Multiple Doors (Routes)

func main() {
    http.HandleFunc("/", homeHandler)
    http.HandleFunc("/users", usersHandler)
    http.HandleFunc("/api/data", apiHandler)

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

func homeHandler(w http.ResponseWriter, r *http.Request) {
    // Check what type of letter arrived
    switch r.Method {
    case "GET":
        fmt.Fprintf(w, "Welcome home!")
    case "POST":
        fmt.Fprintf(w, "Data received!")
    }
}

Reading Incoming Mail

func readRequest(w http.ResponseWriter, r *http.Request) {
    // Who sent it?
    fmt.Println("From:", r.RemoteAddr)

    // What method?
    fmt.Println("Method:", r.Method)

    // Any headers?
    auth := r.Header.Get("Authorization")

    // Query parameters?
    name := r.URL.Query().Get("name")

    // Body content?
    body, _ := io.ReadAll(r.Body)
    fmt.Println("Message:", string(body))
}

โฐ HTTP Context Cancellation: โ€œNever Mind, Forget That Letter!โ€

Sometimes you change your mind. Context lets you cancel requests!

graph TD A["Start Request"] --> B{Context OK?} B -->|Yes| C["Continue Working"] C --> B B -->|Cancelled!| D["Stop Everything"] D --> E["Clean Up"]

Cancel After Some Time

import (
    "context"
    "net/http"
    "time"
)

func cancelableRequest() {
    // "Cancel if not done in 5 seconds"
    ctx, cancel := context.WithTimeout(
        context.Background(),
        5*time.Second,
    )
    defer cancel() // Always clean up!

    req, _ := http.NewRequestWithContext(
        ctx,
        "GET",
        "https://slow-api.example.com",
        nil,
    )

    client := &http.Client{}
    resp, err := client.Do(req)

    if err != nil {
        // Check if cancelled
        if ctx.Err() == context.DeadlineExceeded {
            fmt.Println("Too slow! Cancelled.")
        }
        return
    }
    defer resp.Body.Close()
}

Manual Cancellation

func manualCancel() {
    ctx, cancel := context.WithCancel(
        context.Background(),
    )

    // In another goroutine, cancel when needed
    go func() {
        time.Sleep(2 * time.Second)
        cancel() // "Stop everything!"
    }()

    req, _ := http.NewRequestWithContext(
        ctx, "GET", "https://api.example.com", nil,
    )
    // Request will be cancelled after 2 seconds
}

โฑ๏ธ HTTP Timeouts: Donโ€™t Wait Forever!

Timeouts are like telling the post office: โ€œIf no reply in 10 minutes, forget it!โ€

Client Timeouts

func clientWithTimeout() {
    client := &http.Client{
        Timeout: 10 * time.Second, // Total timeout
    }

    resp, err := client.Get("https://api.example.com")
    if err != nil {
        // Might be timeout!
        fmt.Println("Request failed:", err)
        return
    }
    defer resp.Body.Close()
}

Fine-Grained Control

import "net"

func advancedTimeouts() {
    transport := &http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   5 * time.Second,  // Connect
            KeepAlive: 30 * time.Second,
        }).DialContext,
        TLSHandshakeTimeout:   5 * time.Second,
        ResponseHeaderTimeout: 10 * time.Second,
        IdleConnTimeout:       90 * time.Second,
    }

    client := &http.Client{
        Transport: transport,
        Timeout:   30 * time.Second, // Total
    }

    client.Get("https://api.example.com")
}

Server Timeouts

func serverWithTimeouts() {
    server := &http.Server{
        Addr:         ":8080",
        ReadTimeout:  5 * time.Second,   // Read request
        WriteTimeout: 10 * time.Second,  // Write response
        IdleTimeout:  120 * time.Second, // Keep-alive
    }

    server.ListenAndServe()
}

๐Ÿ”— HTTP Middleware: The Security Guards and Helpers

Middleware are like helpful people who check your letter BEFORE it reaches the final destination. They can check ID, stamp timestamps, or even translate!

graph TD A["Request Arrives"] --> B["Middleware 1: Logging"] B --> C["Middleware 2: Auth Check"] C --> D{Allowed?} D -->|Yes| E["Your Handler"] D -->|No| F["Reject: 401"] E --> G["Response"] G --> B

Creating Middleware

// Middleware is a function that wraps a handler
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            // Before: Log the arrival
            fmt.Printf("[%s] %s %s\n",
                time.Now().Format("15:04:05"),
                r.Method,
                r.URL.Path,
            )

            // Pass to next handler
            next.ServeHTTP(w, r)

            // After: Could log response time
        },
    )
}

Authentication Middleware

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            token := r.Header.Get("Authorization")

            if token == "" {
                http.Error(w, "No token!",
                    http.StatusUnauthorized)
                return
            }

            if !isValidToken(token) {
                http.Error(w, "Bad token!",
                    http.StatusForbidden)
                return
            }

            // Token OK! Continue
            next.ServeHTTP(w, r)
        },
    )
}

Chaining Middleware Together

func main() {
    // Your actual handler
    finalHandler := http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "Secret data!")
        },
    )

    // Wrap with middleware (order matters!)
    // Request goes: logging -> auth -> handler
    wrapped := loggingMiddleware(
        authMiddleware(finalHandler),
    )

    http.Handle("/secret", wrapped)
    http.ListenAndServe(":8080", nil)
}

CORS Middleware Example

func corsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            // Allow cross-origin requests
            w.Header().Set(
                "Access-Control-Allow-Origin", "*",
            )
            w.Header().Set(
                "Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE",
            )

            // Handle preflight
            if r.Method == "OPTIONS" {
                w.WriteHeader(http.StatusOK)
                return
            }

            next.ServeHTTP(w, r)
        },
    )
}

๐ŸŽฏ Quick Reference: Your HTTP Toolbox

Task Tool Example
Simple GET http.Get() http.Get("url")
POST data http.Post() http.Post("url", "type", body)
Custom request http.NewRequest() Full control
Add headers req.Header.Set() Auth, Content-Type
Handle cookies cookiejar.Jar Auto cookie management
Parse URL url.Parse() Break down address
Build URL url.Values Safe query building
Start server http.ListenAndServe() Open for business
Cancel request context.WithTimeout() Prevent hanging
Set timeout client.Timeout Donโ€™t wait forever
Add middleware Wrap handlers Logging, auth, CORS

๐Ÿš€ Youโ€™re Now an HTTP Master!

Youโ€™ve learned:

  • โœ… How to send requests (GET, POST, custom)
  • โœ… Adding special instructions (headers) and membership cards (cookies)
  • โœ… Building smart addresses with query parameters
  • โœ… Taking apart URLs with net/url
  • โœ… Creating your own web server
  • โœ… Cancelling slow requests with context
  • โœ… Setting timeouts so you never wait forever
  • โœ… Building middleware chains for security and logging

Remember: HTTP is just sending letters on the internet. Now go build something amazing! ๐ŸŽ‰

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.