Skip to content
Santekno.com | Level Up Your Engineering Skills
EN
📖 0%
02 Oct 2023 · 4 min read ·Article 61 / 119
Go

02 Learning About HTTP Router Params

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

Use of HTTP Router Params

The httprouter.Handle has an additional parameter, namely Params, which is used to store parameters sent from the client, but this Params is not a query for parameters but is a parameter from the URL. Sometimes we need to create URLs that are not fixed or can change, for example /product/1, /product/2 and so on.

ServerMux does not support this, so on the Router there are additional parameters, one of which is to handle things like this. However, for the Router we need to add something to the Route so that the URL Path becomes dynamic.

How to Implement

Previously we created an easy sample handler and how to call a function so that it can run on the project. Next we will try to create an endpoint that uses a dynamic URL as explained above.

Before going there, we will first change our code so that it is neatly arranged, namely the endpoint that we created in the previous post. become like this.

go
 1package main
 2
 3import (
 4	"net/http"
 5
 6	"github.com/julienschmidt/httprouter"
 7)
 8
 9func main() {
10	router := httprouter.New()
11
12	router.GET("/", SmpleGetHandler)
13	router.POST("/", SamplePostHandler)
14
15	server := http.Server{
16		Handler: router,
17		Addr:    "localhost:8080",
18	}
19
20	server.ListenAndServe()
21}

The code above is the contents of the main.go file. Then we create a new file handler.go whose contents are as below.

go
 1package main
 2
 3import (
 4	"fmt"
 5	"net/http"
 6
 7	"github.com/julienschmidt/httprouter"
 8)
 9
10func SampleGetHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
11	fmt.Fprint(w, "Hello Get")
12}
13
14func SamplePostHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
15	fmt.Fprint(w, "Hello Post")
16}

Once our code is neat, we will continue adding an endpoint that implements dynamic URL params. So, add the code below to the handler.go file.

go
1func GetUsedParamsHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
2	text := "Product " + p.ByName("id")
3	fmt.Fprint(w, text)
4}
Then we call the handler function in the main function like this.
go
1router.GET("/product/:id",GetUsedParamsHandler)

Run the project or program above then try using curl to access the endpoint that we have created like this.

bash
1➜  santekno-hugo git:(main) ✗ curl --location --request GET 'http://localhost:8080/product/1'            
2Product 1%

If we change the parameter 1 then a display will appear that corresponds to the input, for example 2 then Product 2 will appear.

Added Unit Tests

After we create the handler params above, we will also try to ensure that our handler really meets the needs we want, namely by creating a unit test from the function we created earlier. The following is the unit test function for the code above.

go
 1func TestGetUsedParamsHandler(t *testing.T) {
 2	type args struct {
 3		params string
 4	}
 5	tests := []struct {
 6		name string
 7		args args
 8		want string
 9	}{
10		{
11			name: "test get params with product 1",
12			args: args{
13				params: "1",
14			},
15			want: "Product 1",
16		},
17		{
18			name: "test get params with product 2",
19			args: args{
20				params: "2",
21			},
22			want: "Product 2",
23		},
24	}
25	for _, tt := range tests {
26		t.Run(tt.name, func(t *testing.T) {
27			request := httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost/product/%s", tt.args.params), nil)
28			recorder := httptest.NewRecorder()
29			GetUsedParamsHandler(recorder, request, httprouter.Params{
30				{
31					Key:   "id",
32					Value: tt.args.params,
33				},
34			})
35
36			response := recorder.Result()
37			body, _ := io.ReadAll(response.Body)
38			bodyString := string(body)
39
40			assert.Equal(t, tt.want, bodyString)
41		})
42	}
43}
Then we will also add other unit tests to the functions we created previously like this.
go
 1func TestSampleGetHandler(t *testing.T) {
 2	tests := []struct {
 3		name string
 4		want string
 5	}{
 6		{
 7			name: "test get",
 8			want: "Hello Get",
 9		},
10	}
11	for _, tt := range tests {
12		t.Run(tt.name, func(t *testing.T) {
13			request := httptest.NewRequest(http.MethodGet, "http://localhost/", nil)
14			recorder := httptest.NewRecorder()
15			SampleGetHandler(recorder, request, nil)
16
17			response := recorder.Result()
18			body, _ := io.ReadAll(response.Body)
19			bodyString := string(body)
20
21			if !reflect.DeepEqual(bodyString, tt.want) {
22				t.Errorf("response = %v, want %v", bodyString, tt.want)
23			}
24
25			assert.Equal(t, tt.want, bodyString)
26		})
27	}
28}
29
30func TestSamplePostHandler(t *testing.T) {
31	tests := []struct {
32		name string
33		want string
34	}{
35		{
36			name: "test post",
37			want: "Hello Post",
38		},
39	}
40	for _, tt := range tests {
41		t.Run(tt.name, func(t *testing.T) {
42			request := httptest.NewRequest(http.MethodPost, "http://localhost/", nil)
43			recorder := httptest.NewRecorder()
44			SamplePostHandler(recorder, request, nil)
45
46			response := recorder.Result()
47			body, _ := io.ReadAll(response.Body)
48			bodyString := string(body)
49
50			assert.Equal(t, tt.want, bodyString)
51		})
52	}
53}

Related Articles

💬 Comments