No history yet

Standard Library Routing

Handling Web Requests

Go's standard library provides a powerful and lightweight toolkit for building web servers, centered around the net/http package. Unlike frameworks that hide complexity, Go gives you direct control over how incoming network connections are handled.

At the heart of a Go web server is a multiplexer, or mux. The mux is like a traffic cop for your application. It inspects incoming HTTP requests and directs them to the correct handler function based on the URL path. Go provides a ready-to-use instance called the DefaultServeMux.

To start, you register handler functions with this default mux. A handler is just a function that takes two specific arguments: an http.ResponseWriter and a pointer to an http.Request.

package main

import (
	"fmt"
	"net/http"
)

// helloHandler writes a simple greeting.
// This is our handler function. Its signature matches http.HandlerFunc.
func helloHandler(w http.ResponseWriter, r *http.Request) {
	// We only want to handle GET requests at this endpoint.
	if r.Method != http.MethodGet {
		// If it's not a GET, return a 405 Method Not Allowed error.
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	fmt.Fprintf(w, "Hello, web!")
}

func main() {
	// Register helloHandler to handle requests for the URL path "/hello".
	http.HandleFunc("/hello", helloHandler)

	// Start the server on port 8080.
	// ListenAndServe blocks, so it should be the last call in main.
	fmt.Println("Server starting on port 8080...")
	http.ListenAndServe(":8080", nil)
}

The http.HandleFunc function does the registration. The first argument is the URL pattern to match, and the second is the function to execute for that pattern.

The two parameters of any handler function are your tools for managing the HTTP conversation:

  • http.ResponseWriter: An interface used to build and send the HTTP response back to the client. You write headers and the body of the response to it.
  • *http.Request: A struct containing all the information about the incoming request, including the URL, headers, method (GET, POST, etc.), and any data in the request body.

Routing and Pattern Matching

The mux's primary job is to match the path of an incoming request to a registered handler. The rules are simple but powerful. A pattern with a trailing slash, like /assets/, matches any path that has that prefix. A pattern without a trailing slash, like /hello, performs an exact match.

Since Go 1.22, the DefaultServeMux has been enhanced with new features that were previously only available in third-party libraries.

The mux now supports matching on the request method (GET, POST) and including wildcards in the path.

Let's see how this works. We can register a handler that only responds to POST requests and captures a value from the URL path.

package main

import (
	"fmt"
	"net/http"
)

func userHandler(w http.ResponseWriter, r *http.Request) {
	// The wildcard value is available via r.PathValue()
	userID := r.PathValue("id")
	fmt.Fprintf(w, "You are handling a POST request for user %s", userID)
}

func main() {
	// This pattern matches paths like /users/123 or /users/abc.
	// It specifically requires the POST method.
	http.HandleFunc("POST /users/{id}", userHandler)

	fmt.Println("Server starting on port 8080...")
	http.ListenAndServe(":8080", nil)
}

In this example:

  1. POST /users/{id}: This pattern tells the mux to only match POST requests to paths that start with /users/ followed by another segment.
  2. {id}: This is a wildcard. It captures the value in that path segment.
  3. r.PathValue("id"): Inside the handler, we can retrieve the captured value using its name (id).

These additions make the standard library's mux capable enough for many applications without needing external dependencies. For simple and clear routing, it's often the best choice.

If you can use http.ServeMux, you probably should.

Ready to test your knowledge?

Quiz Questions 1/5

What is the primary role of a multiplexer (or mux) in a Go web server built with the net/http package?

Quiz Questions 2/5

Which of the following is the correct function signature for a handler function used with http.HandleFunc?

By mastering the net/http package, you gain a solid foundation for building any kind of web service in Go, from simple APIs to complex distributed systems.