Go Context in HTTP Servers 🎯

beginner
17 min

Go Context in HTTP Servers 🎯

Welcome to a comprehensive guide on using the Go Context in HTTP Servers! In this lesson, we'll cover everything from the basics to advanced examples, making it suitable for both beginners and intermediates. Let's dive in!

Understanding Context 📝

Context is a powerful feature in Go that allows for propagating values across multiple function calls, making it easier to manage timeouts, cancellations, and other request-scoped values.

go
package main import ( "context" "fmt" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() select { case <-time.After(time.Second): fmt.Println("One second passed") case <-ctx.Done(): fmt.Println("Context timed out") } }

In the above example, we create a context with a timeout of 5 seconds and execute two select cases. If the one-second timeout passes, we print "One second passed". If the context times out before that, we print "Context timed out".

Applying Context to HTTP Servers 💡

Now, let's see how we can apply the Context to HTTP servers to manage requests effectively.

go
package main import ( "context" "fmt" "net/http" "time" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() select { case <-time.After(time.Second): fmt.Fprint(w, "One second passed") case <-ctx.Done(): fmt.Fprint(w, "Context timed out") w.WriteHeader(http.StatusGatewayTimeOut) } }) http.ListenAndServe(":8080", nil) }

In this example, we create an HTTP server that responds to any request with either "One second passed" or "Context timed out" based on the context timeout.

Practical Application 🎯

Now, let's make our server more practical by creating a route that performs an expensive operation and uses context for cancellation.

go
package main import ( "context" "fmt" "net/http" "time" ) func longTask(ctx context.Context) { select { case <-ctx.Done(): fmt.Println("Task cancelled") return default: // Simulate an expensive operation time.Sleep(10 * time.Second) fmt.Println("Task completed") } } func handler(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithCancel(r.Context()) go longTask(ctx) // Simulate a user clicking a cancel button if r.URL.Path == "/cancel" { cancel() } fmt.Fprint(w, "Request received") } func main() { http.HandleFunc("/", handler) http.HandleFunc("/cancel", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Cancelling task...") }) http.ListenAndServe(":8080", nil) }

In this example, we create an HTTP server with a route that starts a long-running task. We also create another route for cancelling the task if needed.

Quiz 📝

Quick Quiz
Question 1 of 1

What does the `WithTimeout` function do in Go's Context package?