Menu
Coddy logo textTech

http.Handler Interface

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 77 of 107.

The http.Handler interface is the foundation of Go's web server architecture. It defines how HTTP requests are processed, and any type implementing it can serve web requests.

The interface is remarkably simple:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Any type with a ServeHTTP method can handle HTTP requests. Here's a custom handler:

type GreetHandler struct {
    Greeting string
}

func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}

You can use this handler directly with a server:

handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)

For simpler cases, Go provides http.HandlerFunc, a type that lets you convert a regular function into a handler:

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

http.Handle("/hello", http.HandlerFunc(hello))

The power of this interface becomes clear when you realize that handlers can wrap other handlers. This enables middleware patterns where you add logging, authentication, or other cross-cutting concerns without modifying the original handler logic.

challenge icon

Challenge

Easy

Let's build a simple HTTP handler system that simulates how web requests are processed! Since we can't run an actual HTTP server in this environment, you'll create handlers that implement the http.Handler interface and demonstrate how they process requests by working with mock request/response objects.

You'll organize your code across two files:

  • handlers.go: Define your custom HTTP handlers.

    Create a MockResponseWriter struct that captures what would be written to an HTTP response. It should store the response body as a string and implement a Write(data []byte) (int, error) method that appends data to the body. Add a Body() string method to retrieve the accumulated response.

    Create a MockRequest struct with Path and Method string fields to simulate an HTTP request.

    Now create two handler structs that implement the http.Handler interface pattern (with a ServeHTTP method that takes a *MockResponseWriter and *MockRequest):

    • WelcomeHandler with a Message field - writes the message followed by the request path
    • MethodHandler - writes different responses based on the request method: "Fetching data" for GET, "Creating resource" for POST, and "Method not supported" for anything else
  • main.go: Process requests through your handlers.

    Read a handler type (welcome or method), then read request details. For the welcome handler, also read the welcome message.

    Create the appropriate handler, build a mock request, and call ServeHTTP to process it. Print the response body.

The following inputs will be provided:

  • Line 1: Handler type (welcome or method)
  • Line 2: Request path
  • Line 3: Request method
  • Line 4 (only for welcome): Welcome message

For example, given:

welcome
/home
GET
Hello from

Your output should be:

Hello from /home

And given:

method
/api/users
POST

Your output should be:

Creating resource

And given:

method
/api/data
GET

Your output should be:

Fetching data

And given:

method
/api/items
DELETE

Your output should be:

Method not supported

This challenge demonstrates the core concept of the http.Handler interface—any type with a ServeHTTP method can handle requests. In real applications, the http.ResponseWriter and *http.Request come from Go's standard library, but the pattern of implementing handlers remains exactly the same.

Cheat sheet

The http.Handler interface is the foundation of Go's web server architecture:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Any type with a ServeHTTP method can handle HTTP requests:

type GreetHandler struct {
    Greeting string
}

func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}

Register a handler with the server:

handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)

For simpler cases, use http.HandlerFunc to convert a function into a handler:

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

http.Handle("/hello", http.HandlerFunc(hello))

Handlers can wrap other handlers, enabling middleware patterns for logging, authentication, or other cross-cutting concerns.

Try it yourself

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Read handler type
	scanner.Scan()
	handlerType := scanner.Text()
	
	// Read request path
	scanner.Scan()
	path := scanner.Text()
	
	// Read request method
	scanner.Scan()
	method := scanner.Text()
	
	// Create mock request
	request := &MockRequest{
		Path:   path,
		Method: method,
	}
	
	// Create mock response writer
	response := &MockResponseWriter{}
	
	// TODO: Based on handlerType, create the appropriate handler
	// If handlerType is "welcome", read the welcome message and create WelcomeHandler
	// If handlerType is "method", create MethodHandler
	// Call ServeHTTP on the handler with response and request
	
	if handlerType == "welcome" {
		scanner.Scan()
		message := scanner.Text()
		// TODO: Create WelcomeHandler with the message and call ServeHTTP
		_ = message // Remove this line when implementing
	} else if handlerType == "method" {
		// TODO: Create MethodHandler and call ServeHTTP
	}
	
	// Print the response body
	fmt.Println(response.Body())
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming