← Back to Go Course | Chapter 14: Standard Library & HTTP | Lesson 7 of 10

Basic HTTP Server

An HTTP server is a program that sits and listens for visitors (web requests) knocking on a specific door (port), and answers each one with a response.

Writing a Handler Function

An HTTP handler is a function matching func(w http.ResponseWriter, r *http.Request), where writing to w sends bytes back as the response body to whoever made the request.

Example: Writing a Handler Function

markup
package main

import (
	"fmt"
	"net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Hello from a Go HTTP handler!")
}

func main() {
	http.HandleFunc("/hello", helloHandler)
	fmt.Println("handler registered for /hello")
}

Testing a Handler Without a Real Server

Since starting a real listener would block forever in this sandbox, handlers can be exercised directly using httptest.NewRecorder and httptest.NewRequest, which simulate an HTTP request/response without opening any actual network socket.

Note: net/http/httptest is the standard way to test handlers without binding a real network port.

Example: Testing a Handler Without a Real Server

markup
package main

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

func helloHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Hello, HTTP!")
}

func main() {
	req := httptest.NewRequest(http.MethodGet, "/hello", nil)
	rec := httptest.NewRecorder()

	helloHandler(rec, req)

	fmt.Println("status:", rec.Code)
	fmt.Println("body:", rec.Body.String())
}

Setting a Status Code

w.WriteHeader(code) explicitly sets the HTTP status code for the response before any body is written -- omitting it defaults to 200 OK once the first write happens.

Note: Call WriteHeader before any call to Write/Fprintln, since the status line must go out first.

Example: Setting a Status Code

markup
package main

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

func notFoundHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintln(w, "resource not found")
}

func main() {
	req := httptest.NewRequest(http.MethodGet, "/missing", nil)
	rec := httptest.NewRecorder()
	notFoundHandler(rec, req)
	fmt.Println("status:", rec.Code, "body:", rec.Body.String())
}
Common Mistakes
  1. Calling http.ListenAndServe in an interactive/CI sandbox, which blocks forever waiting for real network connections -- runnable examples here should call handlers directly instead of actually starting a listener.
  2. Registering the same route pattern twice with http.HandleFunc, which panics at startup.
  3. Forgetting to write an HTTP status code before writing the body when a non-200 response is needed -- WriteHeader must be called before Write.
Chapter Summary
  • http.HandleFunc registers a function to handle requests matching a URL pattern.
  • A handler function receives an http.ResponseWriter (to write the response) and an *http.Request (describing the incoming request).
  • http.ListenAndServe starts the server, blocking and listening for connections on a given address.
  • http.NewRequest plus calling a handler directly is a simple way to demonstrate handler logic without a real network listener.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.