>_
GolangStepByStep
Software Engineer

API Design in Go

Package boundaries, public surface minimization, clean APIs

# What is an API? (The Restaurant Analogy)

Imagine you walk into a fast-food restaurant. You stand at the counter. The kitchen in the back is bustling, doing highly complex work: frying, wrapping, assembling logic, managing inventory (the Database).

You, the customer (the Client), cannot just walk into the kitchen and fry your own burger. That would be chaotic. Instead, you speak to the cashier. The cashier accepts your formatted spoken request ("I'll have a number 1 combo"), relays it to the kitchen safely, and hands you a tidy tray of food in response.

An API (Application Programming Interface) is that cashier. Go is exceptional at building these cashiers. Its standard net/http package is so powerful that many massive tech companies use it to serve billions of requests without needing bulky third-party frameworks.

# Level 1: The Basic Server (Beginner)

Building a web server in Go requires three simple steps: 1. Write a function that handles an order. 2. Tell the server what URL matches that function (Routing). 3. Turn the server on.

Every handler in Go uses the exact same signature: it takes an http.ResponseWriter (the tray where you put the food to give back) and an *http.Request (the slip of paper showing what the user ordered).

package main

import (
    "fmt"
    "net/http"
)

// Step 1: Writing the Handler
func helloHandler(w http.ResponseWriter, r *http.Request) {
    // "w" is where we write our response
    fmt.Fprintln(w, "Hello, Customer! Welcome to Go-Burger.")
}

func main() {
    // Step 2: Routing - linking a path to our function
    http.HandleFunc("/hello", helloHandler)

    // Step 3: Turn it on! (Fires up on port 8080)
    fmt.Println("Server is running on http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

# Level 2: Speaking JSON (Intermediate)

Modern APIs don't just speak plain text; they speak JSON (JavaScript Object Notation). It's the universal language of the web.

To format Go structs into JSON, we use Go Struct Tags. This tells Go's `encoding/json` package how to translate the uppercase Go fields into nice lowercase JSON keys.

package main

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

// 1. Define your data model with JSON tags
type Order struct {
    ItemName string `json:"item_name"`
    Price    int    `json:"price"`
}

func orderHandler(w http.ResponseWriter, r *http.Request) {
    // 2. Set the header so the client knows we are sending JSON
    w.Header().Set("Content-Type", "application/json")
    
    myOrder := Order{
        ItemName: "Double Cheeseburger",
        Price:    599, // In cents!
    }
    
    // 3. Encode the struct directly onto the ResponseWriter (the tray)
    json.NewEncoder(w).Encode(myOrder)
}

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

Tip: Always set the Content-Type header to application/json before sending data, so the browser properly formats it!

# Level 3: Middleware - The Bouncer (Advanced)

Imagine you have a VIP lounge in your restaurant. You don't want the kitchen staff checking IDs; you want a Bouncer at the door.

In Go, this is called Middleware. Middleware is a function that takes a Handler, does some work (like checking for an ID or logging the time), and then passes the request smoothly to the real Handler.

// The Bouncer Middleware!
func LoggingMiddleware(next http.Handler) http.Handler {
    // We return a new handler that wraps the old "next" one
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        
        // 1. DO WORK BEFORE HANDLER: Log the incoming request method and path
        log.Printf("Bouncer spotted a request: %s %s", r.Method, r.URL.Path)

        // 2. PASS IT ALONG: Let the actual kitchen staff handle it
        next.ServeHTTP(w, r)
        
        // 3. DO WORK AFTER HANDLER: (Optional) Action after the response is sent
    })
}

func main() {
    // Set up our basic multiplexer (router)
    mux := http.NewServeMux()
    
    // Convert our standard func into an http.Handler
    finalHandler := http.HandlerFunc(helloHandler)
    
    // WRAP the final handler in our Middleware Bouncer!
    mux.Handle("/hello", LoggingMiddleware(finalHandler))

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

# Level 4: Graceful Shutdowns and Context (Expert)

When it's time to close the restaurant for the night, you don't instantly throw all the cooking food in the trash and kick out paying customers who are mid-bite. You flip the sign to "Closed", lock the door so new customers can't enter, but you let the existing diners finish their meals.

This is a Graceful Shutdown. When deploying an update, you want your server to stop taking new requests, finish the ones it's currently processing, and then exit safely.

func main() {
    server := &http.Server{Addr: ":8080", Handler: mux}

    // 1. Run the server in a separate goroutine so it doesn't block the main thread
    go func() {
        if err := server.ListenAndServe(); err != http.ErrServerClosed {
            log.Fatalf("Server exploded: %v", err)
        }
    }()

    // 2. Create a channel to listen for keyboard Interrupts (Ctrl+C / SIGINT)
    quit := make(chan os.Signal, 1)
    
    // 3. Notify the channel when the OS says "shut down"
    signal.Notify(quit, os.Interrupt)
    
    // 4. Pauses main() until a signal is received
    <-quit
    log.Println("Shutting down the restaurant gracefully...")

    // 5. Give the server 5 seconds to let current clients finish
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    // Shutdown safely! No new connections. Waits for active ones (up to 5s).
    server.Shutdown(ctx)
    log.Println("Restaurant closed successfully. Goodnight!")
}

This pattern is the hallmark of professional, production-ready Go applications. Without it, every time you deploy a bugfix or feature, you might sever hundreds of active connections instantly resulting in 502 Bad Gateway errors for your users.

practice & review