No history yet

Go HTTP Foundations

Starting a Go Web Server

In Node.js, you'd typically reach for a framework like Express to get a server running. Go handles this differently. Its standard library includes a powerful package, net/http, that provides everything you need to build robust web services without any external dependencies.

The core function for starting a server is http.ListenAndServe. It does exactly what its name suggests: it listens on a network address for incoming HTTP connections and serves responses.

package main

import (
	"fmt"
	"log"
	"net/http"
)

// helloHandler responds to requests with a simple greeting.
func helloHandler(w http.ResponseWriter, r *http.Request) {
	// We use Fprintf to write the string into the ResponseWriter.
	fmt.Fprintf(w, "Hello, Web!")
}

func main() {
	// Register helloHandler to handle all requests to the web root.
	http.HandleFunc("/", helloHandler)

	// Start the server on port 8080.
	// The second argument `nil` tells it to use the default router.
	log.Println("Server starting on port 8080...")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

This code starts a server on port 8080. The first argument to ListenAndServe is the address. The second, nil, tells Go to use the default request router, known as DefaultServeMux. We use http.HandleFunc to tell this default router that any request for the path / should be handled by our helloHandler function. Wrapping the server start in log.Fatal ensures that if the server fails to start (for example, if the port is already in use), the program will exit and log the error.

Handling a Request

Every handler function in Go's net/http package receives two crucial arguments: an http.ResponseWriter and a pointer to an http.Request.

func(w http.ResponseWriter, r *http.Request)

The http.Request is a struct that holds all the information about the incoming request from the client. This includes the URL, headers, any data in the request body, and more. It's how you read what the client is asking for.

The http.ResponseWriter is an interface that your handler uses to construct and send the response back to the client. You use it to set the status code, write headers, and send the response body. In our example, fmt.Fprintf(w, ...) writes the string directly to the response body.

Go's Concurrency Model

This is where Go diverges significantly from Node.js. Node uses a single-threaded, event-driven model. An event loop handles all incoming requests, and long-running operations are managed asynchronously with callbacks or promises to avoid blocking the main thread.

Go takes a different approach. The net/http server is built on Go's lightweight concurrency primitives, called goroutines. Every time the server accepts a new connection, it spawns a new goroutine to handle that request. This means each request runs independently and concurrently with all other requests.

This model simplifies writing concurrent code. You don't need to worry about managing an event loop. If one request handler is performing a slow operation (like a database query), it doesn't block other requests from being served. The Go runtime manages scheduling the goroutines efficiently across the available CPU cores.

The Handler Interface

So far, we've used http.HandleFunc, which is a convenient wrapper. Under the hood, Go's net/http package relies on the http.Handler interface. Any type that implements this interface can serve HTTP requests.

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

The interface is simple: it requires a single method, ServeHTTP, which has the same signature as the handler functions we've been writing. While HandleFunc is great for simple cases, creating a struct that implements the Handler interface allows you to manage state, dependencies (like a database connection), and more complex logic within your handler.

We'll explore this more advanced pattern later. For now, understanding http.ListenAndServe, handler functions, ResponseWriter, and Request provides a solid foundation for building web services in Go.

Quiz Questions 1/5

In Go's net/http package, which function is primarily used to start a web server and have it listen on a specific network address?

Quiz Questions 2/5

What is the primary role of the http.ResponseWriter argument in a handler function?

With these building blocks, you can create a simple but fully functional web server using only Go's standard library.