Web App Testing – Middleware – Persiapan

Untuk keperluan tutorial ini, kita akan tambahkan middleware pada webapp. Middleware yang digunakan adalah untuk mendapatkan informasi IP address.

Buat file baru cmd/web/middleware.go, gunakan kode berikut:

package main

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

type contextkey string

const contextUserKey contextkey = "user_ip"

func (app *application) ipFromContext(ctx context.Context) string {
	return ctx.Value(contextUserKey).(string)
}

func (app *application) addIPToContext(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var ctx = context.Background()

		ip, err := getIP(r)

		if err != nil {
			ip, _, _ := net.SplitHostPort(r.RemoteAddr)
			if len(ip) == 0 {
				ip = "unknown"
			}
			ctx = context.WithValue(r.Context(), contextUserKey, ip)
		} else {
			ctx = context.WithValue(r.Context(), contextUserKey, ip)
		}
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func getIP(r *http.Request) (string, error) {
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return "unknown", err
	}

	userIP := net.ParseIP(ip)
	if userIP == nil {
		return "", fmt.Errorf("userip: %q is not IP:port", r.RemoteAddr)
	}

	forward := r.Header.Get("X-Forwarded-For")
	if len(forward) > 0 {
		ip = forward
	}

	if len(ip) == 0 {
		ip = "forward"
	}

	return ip, nil
}

Kemudian buka file cmd/web/routes.go, lalu modifikasi seperti kode dibawah.

package main

import (
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func (app *application) routes() http.Handler {
	mux := chi.NewRouter()

	//register middleware
	mux.Use(middleware.Recoverer)
	mux.Use(app.addIPToContext) //tambahkan middleware yang kita buat

	//register routes
	mux.Get("/", app.Home)

	//static assets

	fileServer := http.FileServer(http.Dir("./static"))
	mux.Handle("/static/*", http.StripPrefix("/static/", fileServer))

	return mux
}

Kemudian modifikasi file cmd/web/handlers.go, untuk menggunakan middleware yang telah kita buat diatas.

package main

import (
	"html/template"
	"net/http"
	"path"
)

var templatePath = "./templates/"

func (app *application) Home(w http.ResponseWriter, r *http.Request) {
	_ = app.render(w, r, "home.page.gohtml", &TemplateData{})
}

type TemplateData struct {
	IP   string
	Data map[string]any
}

func (app *application) render(w http.ResponseWriter, r *http.Request, t string, data *TemplateData) error {
	//parse template
	parsedTemplate, err := template.ParseFiles(path.Join(templatePath, t))
	if err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return err
	}

	//gunakan middleware yang telah kita buat.
	data.IP = app.ipFromContext(r.Context())

	//execute template
	err = parsedTemplate.Execute(w, data)
	if err != nil {
		return err
	}
	return nil
}

Selanjutnya, IP yang telah kita baca menggunakan middleware, akan ditampilkan dalam file template. Buka file templates/home.page.gohtml, lalu modifikasi seperti berikut:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
    <title>Home</title>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col">
                <h1 class="mt-3">Home Page</h1>
                <hr>
                <small>Your request from: {{.IP}}</small>
            </div>
        </div>
    </div>
</body>
</html>

JIka kita test, pada web browser akan ditampilkan seperti berikut: (windows 10 menggunakan IPv6 secara default, maka ditampilkan ::1. Pada os lain akan tampil 127.0.0.1).

Sharing is caring:

Leave a Comment