Loading...
Loading...

Go Web Servers and REST APIs Tutorial

Go's net/http package provides robust tools for building web servers and APIs. This tutorial walks through creating servers, handling routes, processing requests, and building RESTful endpoints.

1. Basic HTTP Server

1.1 Creating a Simple Server

The foundation of Go web development starts with the http.HandleFunc and http.ListenAndServe functions:

package main

import (
    "fmt"
    "net/http"
)

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

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

Key Components:

  • http.HandleFunc: Registers a route ("/") with a handler function
  • http.ResponseWriter: Interface for writing response data
  • *http.Request: Contains all incoming request data
  • ListenAndServe: Starts server on specified port

2. Request Handling

2.1 Reading Request Data

Go provides several ways to access incoming request data:

func requestHandler(w http.ResponseWriter, r *http.Request) {
    // Read URL query parameters
    query := r.URL.Query().Get("search")
    
    // Read headers
    contentType := r.Header.Get("Content-Type")
    
    // Read JSON body
    var data struct { Name string `json:"name` }
    json.NewDecoder(r.Body).Decode(&data)
    
    // Read form data
    r.ParseForm()
    email := r.FormValue("email")
}

Key Methods:

  • URL.Query(): Access query string parameters
  • Header.Get(): Read specific headers
  • Body: Stream for reading request body
  • FormValue(): Get form/post data

3. REST API Design

3.1 Resource-Based Routing

Proper REST APIs use HTTP methods to perform CRUD operations:

func main() {
    router := mux.NewRouter()
    
    // RESTful routes
    router.HandleFunc("/users", getUsers).Methods("GET")
    router.HandleFunc("/users", createUser).Methods("POST")
    router.HandleFunc("/users/{id}", getUser).Methods("GET")
    router.HandleFunc("/users/{id}", updateUser).Methods("PUT")
    router.HandleFunc("/users/{id}", deleteUser).Methods("DELETE")
    
    http.ListenAndServe(":8080", router)
}

REST Principles:

  • GET: Retrieve resources
  • POST: Create new resources
  • PUT/PATCH: Update existing resources
  • DELETE: Remove resources
  • {id}: URL parameters for specific resources

4. Middleware

4.1 Creating Middleware

Middleware functions process requests before they reach handlers:

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        // Call next handler
        next.ServeHTTP(w, r)
        
        // Log after request completes
        log.Printf(
            "%s %s %s",
            r.Method,
            r.URL.Path,
            time.Since(start),
        )
    })
}

func main() {
    router := mux.NewRouter()
    router.Use(loggingMiddleware)
    // ... routes
}

Middleware Characteristics:

  • Wraps handlers: Processes requests before/after handlers
  • Chainable: Multiple middleware can be combined
  • Common uses: Logging, auth, CORS, compression

5. Error Handling

5.1 Structured Error Responses

APIs should return consistent error formats:

func getUser(w http.ResponseWriter, r *http.Request) {
    id := mux.Vars(r)["id"]
    user, err := db.GetUser(id)
    
    if err != nil {
        w.WriteHeader(http.StatusNotFound)
        json.NewEncoder(w).Encode(map[string]string{
            "error": "User not found",
        })
        return
    }
    
    json.NewEncoder(w).Encode(user)
}

Best Practices:

  • HTTP status codes: 404 for not found, 400 for bad requests
  • JSON responses: Machine-readable error details
  • Consistent format: Same structure for all errors

6. Advanced Patterns

6.1 Context and Timeouts

Prevent long-running requests with context timeouts:

func slowHandler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    
    select {
    case <-time.After(5 * time.Second):
        fmt.Fprint(w, "Done")
    case <-ctx.Done():
        err := ctx.Err()
        log.Println("Request canceled:", err)
        http.Error(w, err.Error(), http.StatusGatewayTimeout)
    }
}

Key Benefits:

  • Prevents resource leaks: Automatically cancel long requests
  • Graceful timeout handling: Proper error responses
  • Propagates cancellation: Through entire call chain
0 Interaction
0 Views
Views
0 Likes
×
×
×
🍪 CookieConsent@Ptutorials:~

Welcome to Ptutorials

$ Allow cookies on this site ? (y/n)

top-home