programming

07 How to Understanding Cookie in Golang

Introduction to Cookies

Before discussing Cookies, we need to know that HTTP is stateless between client and server, which means the server does not store any data to remember every request from the client. This aims to make it easy to scale the server itself. So how do you get the server to remember a client? for example, when we have logged in to a website, the server must automatically know that the client has logged in so that subsequent requests no longer require logging in. For things like this, we can usually use Cookies.

Cookies are an HTTP feature which is provided by the server through a cookie response (key-value) and the client will store the cookie in the web browser. This way, when the client makes the next request, the client will always bring the cookie automatically. And the server will automatically always receive the cookie data brought by the client every time the client makes a request.

In Golang, we can use the http.SetCookie function to use cookies on the server so that later the client can automatically use cookies in its requests.

Implementation

Now we will try to understand it more deeply by providing an example like the code below.

func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
	cookie := new(http.Cookie)
	cookie.Name = "X-PXN-Name"
	cookie.Value = r.URL.Query().Get("name")
	cookie.Path = "/"
	http.SetCookie(w, cookie)
	fmt.Fprintf(w, "Success create cookie")
}

func GetCookieHandler(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("X-PXN-Name")
	if err != nil {
		fmt.Fprint(w, "no cookie")
	} else {
		fmt.Fprintf(w, "hello %s", cookie.Value)
	}
}

So that we can see in the browser whether the cookie has been set or not, we need to add more to the main.go file as below.


func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/set-cookie", SetCookieHandler)
	mux.HandleFunc("/get-cookie", GetCookieHandler)

	server := http.Server{
		Addr:    "localhost:8080",
		Handler: mux,
	}

	err := server.ListenAndServe()
	if err != nil {
		panic(err)
	}
}

How to carry out tests or tests by running the program.

go build && ./learn-golang-web

Then we open the Chrome or Mozilla browser and do an inspect element. If it has been accessed using a browser it will look like the image below.

web set cookie

Then when we access another handler to get cookies at the URL http://localhost:8080/get-cookie, it will look like the image below.

web get cookie

We test the function above which will set a cookie on the endpoint handler so that we know that the cookie being set is as set in the function.

func TestSetCookieHandler(t *testing.T) {
	type args struct {
		name string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "set cookie",
			args: args{
				name: "santekno",
			},
			want: "santekno",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://localhost/say?name=%s", tt.args.name), nil)
			recorder := httptest.NewRecorder()
			SetCookieHandler(recorder, request)

			cookies := recorder.Result().Cookies()

			for _, cookie := range cookies {
				if !reflect.DeepEqual(cookie.Value, tt.want) {
					t.Errorf("response = %s, want %s", cookie.Value, tt.want)
				}
			}

		})
	}
}

And we also do a unit test for the get cookie function below.

func TestGetCookieHandler(t *testing.T) {
	type args struct {
		name string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "get cookie handler without cookie",
			args: args{
				name: "",
			},
			want: "no cookie",
		},
		{
			name: "get cookie handler with cookie",
			args: args{
				name: "santekno",
			},
			want: "hello santekno",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, "http://localhost/say", nil)
			if tt.args.name != "" {
				cookie := new(http.Cookie)
				cookie.Name = "X-PXN-Name"
				cookie.Value = tt.args.name
				request.AddCookie(cookie)
			}

			recorder := httptest.NewRecorder()
			GetCookieHandler(recorder, request)

			response := recorder.Result()
			body, _ := io.ReadAll(response.Body)
			bodyString := string(body)

			if !reflect.DeepEqual(bodyString, tt.want) {
				t.Errorf("response = %s, want %s", bodyString, tt.want)
			}
		})
	}
}
comments powered by Disqus