programming

09 How to Set Headers on Requests and Responses Using Httprouter in Golang

In web development, managing HTTP request and response headers is crucial for handling data, security, and metadata. This article provides a step-by-step guide on setting headers using the httprouter library in Golang. With this guide, even beginners can grasp the concept with ease.


Prerequisites

Before getting started, ensure you have the following:

  1. Golang Installed: Make sure Go is installed on your system.
  2. New Project Setup: Create a new project with a basic file structure.
  3. Httprouter Library: Install the httprouter library with the following command:
    go get github.com/julienschmidt/httprouter
    

Step 1: Setting Up the Project Structure

Create the following project structure:

project/
├── main.go
└── handlers/
    └── headers.go

Step 2: Setting Headers in Responses

Response headers are sent to the client via the http.ResponseWriter object. Let’s add a handler to set response headers.

1. Creating the Handlers File

Open handlers/headers.go and add the following code:

package handlers

import (
	"net/http"
	"github.com/julienschmidt/httprouter"
)

// ResponseHeaderHandler adds headers to the response
func ResponseHeaderHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Custom-Header", "Learning Golang")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"message":"Headers set successfully!"}`))
}

2. Connecting the Handler in main.go

Open main.go and add the following handler:

package main

import (
	"log"
	"net/http"
	"github.com/julienschmidt/httprouter"
	"project/handlers"
)

func main() {
	router := httprouter.New()

	// Add the response header handler
	router.GET("/set-response-header", handlers.ResponseHeaderHandler)

	log.Println("Server running at http://localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", router))
}

3. Testing the Endpoint

Run the server:

go run main.go

Access the endpoint via a browser or use curl:

curl -i http://localhost:8080/set-response-header

The response will display the headers that have been set.


Step 3: Setting Headers in Requests

To manipulate request headers, we can use the http.Request object. Here, we’ll create middleware that reads and processes request headers.

1. Adding Middleware

Open handlers/headers.go again and add the following function:

// RequestHeaderHandler processes headers from the request
func RequestHeaderHandler(next httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		headerValue := r.Header.Get("X-Requested-By")
		if headerValue == "" {
			http.Error(w, "X-Requested-By header missing", http.StatusBadRequest)
			return
		}

		next(w, r, ps)
	}
}

2. Adding Middleware to main.go

Modify main.go to use the middleware:

router.GET("/validate-request-header", handlers.RequestHeaderHandler(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Write([]byte("Header valid!"))
}))

3. Testing the Endpoint

Run the server again and use curl:

curl -i -H "X-Requested-By: ClientApp" http://localhost:8080/validate-request-header

If the header is valid, the response will be:

Header valid!

If the header is missing, the response will show an error:

X-Requested-By header missing

Step 4: Writing Unit Tests

Writing unit tests ensures our functions work as expected.

1. Testing ResponseHeaderHandler

Create handlers/headers_test.go and add the following test:

package handlers

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"github.com/julienschmidt/httprouter"
)

func TestResponseHeaderHandler(t *testing.T) {
	req := httptest.NewRequest("GET", "/set-response-header", nil)
	w := httptest.NewRecorder()
	params := httprouter.Params{}

	ResponseHeaderHandler(w, req, params)

	resp := w.Result()
	if resp.Header.Get("X-Custom-Header") != "Learning Golang" {
		t.Errorf("Expected X-Custom-Header to be Learning Golang, got %s", resp.Header.Get("X-Custom-Header"))
	}
}

2. Testing RequestHeaderHandler

func TestRequestHeaderHandler(t *testing.T) {
	handler := RequestHeaderHandler(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		w.Write([]byte("Header valid!"))
	})

	req := httptest.NewRequest("GET", "/validate-request-header", nil)
	w := httptest.NewRecorder()
	params := httprouter.Params{}

	// Case: Missing Header
	handler(w, req, params)
	if w.Code != http.StatusBadRequest {
		t.Errorf("Expected status 400, got %d", w.Code)
	}

	// Case: Valid Header
	req.Header.Set("X-Requested-By", "ClientApp")
	w = httptest.NewRecorder()
	handler(w, req, params)
	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}
}

Run the tests using:

go test ./handlers

Conclusion

With httprouter, you can easily set headers on HTTP requests and responses. Managing headers is crucial for client-server communication, including security enforcement, caching control, and metadata handling.

For those looking to dive deeper, explore concepts like middleware chaining to manage multiple logic flows modularly. Additionally, consider using debugging tools like Postman or Insomnia to visually test headers, or add logging to your middleware to track headers during development.

We hope this guide helps you better understand header management in Golang web development. If you have any questions, feel free to discuss!

You can also explore related articles:

comments powered by Disqus