programming

03 How To Used Query Parameter in Golang

Introduction to Query Parameters

Query parameters are one of the features of http that we usually use to send data from the client to the server. This parameter query is placed in the URL of the endpoint that we have created. To add query parameters, we can use ?=name=value in our website URL.

Package url.URL

The package that we use to recognize query parameters is url.URL in the request parameter. From this URL we can retrieve query parameter data sent from the client using the Query() method with map type data returns.

For example, we will create a handler that accepts parameters from the client as below.

func SayHelloParameterHandler(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get("name")
	if name == "" {
		fmt.Fprint(w, "Hello")
	} else {
		fmt.Fprintf(w, "Hello %s", name)
	}
}

We need to prove this function works well, we need to add a unit test as below.

func TestSayHelloParameterHandler(t *testing.T) {
	type args struct {
		name string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "success return response with name",
			args: args{
				name: "santekno",
			},
			want: "Hello santekno",
		},
		{
			name: "success return response without name",
			args: args{
				name: "",
			},
			want: "Hello",
		},
	}
	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()
			SayHelloParameterHandler(recorder, request)

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

			if !reflect.DeepEqual(bodyString, tt.want) {
				t.Errorf("response = %v, want %v", bodyString, tt.want)
			}
		})
	}
}

Multiple Query Parameters

When we want to receive more than one parameter sent by the client, this URL specification can support sending many parameters to the server by using the & sign followed by querying the next parameter.

For example, the client sends two query parameters and will later be received by the server with the handler below.

func MultipleParameterHandler(w http.ResponseWriter, r *http.Request) {
	firstName := r.URL.Query().Get("first_name")
	lastName := r.URL.Query().Get("last_name")
	if firstName == "" && lastName == "" {
		fmt.Fprint(w, "Hello")
	} else {
		fmt.Fprintf(w, "Hello %s %s", firstName, lastName)
	}
}

Let’s try to test the results of the function we created above by creating the unit test below.

func TestMultipleParameterHandler(t *testing.T) {
	type args struct {
		firstName string
		lastName  string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "success return response with name",
			args: args{
				firstName: "Santekno",
				lastName:  "Inc",
			},
			want: "Hello Santekno Inc",
		},
		{
			name: "success return response without name",
			args: args{
				firstName: "",
				lastName:  "",
			},
			want: "Hello",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://localhost/say?first_name=%s&last_name=%s", tt.args.firstName, tt.args.lastName), nil)
			recorder := httptest.NewRecorder()
			MultipleParameterHandler(recorder, request)

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

			if !reflect.DeepEqual(bodyString, tt.want) {
				t.Errorf("response = %v, want %v", bodyString, tt.want)
			}
		})
	}
}

Multiple Value Query Parameters

We can actually parse the query parameter URL query and store it in the type map[string][]string. This means that in one key query parameter we can enter several values. How to? by adding a name parameter with the same name but different values, for example:

name=Santekno&name=Ihsan

Previously we used the Get() method to get the data, because currently the condition is multiple values so we cannot use this method. So, there are other ways that we can retrieve this data.

func MultipleParameterValueHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	names := query["name"]
	if len(names) == 0 {
		fmt.Fprint(w, "Hello")
	} else {
		fmt.Fprintf(w, "Hello %s", strings.Join(names, " "))
	}
}

We try to do a test by creating a unit test to ensure the data matches the parameters sent.

func TestMultipleParameterValueHandler(t *testing.T) {
	type args struct {
		name []string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "success return response with name",
			args: args{
				name: []string{"santekno", "ihsan"},
			},
			want: "Hello santekno ihsan",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://localhost/say?name=%s&name=%s", tt.args.name[0], tt.args.name[1]), nil)
			recorder := httptest.NewRecorder()
			MultipleParameterValueHandler(recorder, request)

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

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