Penggunaan HTTP Router Params
Pada httprouter.Handle
memiliki parameter tambahan yaitu Params
yang mana parameter tersebut digunakan untuk menyimpan parameter yang dikirim dari client tetapi Params
ini bukan query dari parameter
melainkan yaitu parameter dari URL. Kadang kita butuh untuk membuat URL yang tidak fix atau bisa berubah-ubah misalkan /product/1
, /product/2
dan seterusnya.
Pada ServerMux tidak mendukung hal tersebut maka pada Router ada tambahan parameter tersebut salah satunya untuk menangani seperti ini. Namun agar Router kita perlu menambahkan sesuatu pada Route agar URL Path tersebut menjadi dinamis.
Cara Implementasi
Sebelumnya kita membuat sample handler yang mudah dan bagaimana cara memanggil suatu fungsinya agar bisa berjalan pada projeknya. Selanjutnya kita akan mencoba membuat satu endpoint yang menggunakan URL dinamis seperti yang dijelaskan diatas.
Sebelum kesana akan mengubag terlebih dahulu kode kita agar tersusun dengan rapi yaitu endpoint yang sudah kita buat pada postingan sebelumnya. menjadi seperti ini.
package main
import (
"net/http"
"github.com/julienschmidt/httprouter"
)
func main() {
router := httprouter.New()
router.GET("/", SmpleGetHandler)
router.POST("/", SamplePostHandler)
server := http.Server{
Handler: router,
Addr: "localhost:8080",
}
server.ListenAndServe()
}
Kode diatas merupakan isi dari file main.go
. Lalu kita buat file baru handler.go
yang isinya seperti dibawah ini.
package main
import (
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func SampleGetHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
fmt.Fprint(w, "Hello Get")
}
func SamplePostHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
fmt.Fprint(w, "Hello Post")
}
Setelah kode kita sudah rapi, lanjut kita akan menambahkan satu endpoint yang mengimplementasikan params URL dinamis. Maka, tambahkan kode dibawah ini pada file handler.go
.
func GetUsedParamsHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
text := "Product " + p.ByName("id")
fmt.Fprint(w, text)
}
Lalu kita panggil fungsi handler-nya itu pada fungsi main seperti ini.
router.GET("/product/:id",GetUsedParamsHandler)
Jalankan project atau program diatas lalu kita coba gunakan curl untuk mengakses endpoint yang sudah kita buat seperti ini.
➜ santekno-hugo git:(main) ✗ curl --location --request GET 'http://localhost:8080/product/1'
Product 1%
Jika kita mengubah parameter 1
maka nanti juga akan muncul tampilan yang sesuai dengan input misalkan 2
maka akan keluar Product 2
.
Menambahkan Unit Test
Setelah kita buat params handler yang diatas kita juga akan mencoba memastikan handler kita itu benar-benar sesuai dengan kebutuhan yang kita inginkan yaitu dengan cara membuat unit test dari fungsi yang tadi sudah kita buat. Berikut ini fungsi unit test untuk kode yang diatas.
func TestGetUsedParamsHandler(t *testing.T) {
type args struct {
params string
}
tests := []struct {
name string
args args
want string
}{
{
name: "test get params with product 1",
args: args{
params: "1",
},
want: "Product 1",
},
{
name: "test get params with product 2",
args: args{
params: "2",
},
want: "Product 2",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost/product/%s", tt.args.params), nil)
recorder := httptest.NewRecorder()
GetUsedParamsHandler(recorder, request, httprouter.Params{
{
Key: "id",
Value: tt.args.params,
},
})
response := recorder.Result()
body, _ := io.ReadAll(response.Body)
bodyString := string(body)
assert.Equal(t, tt.want, bodyString)
})
}
}
Lalu kita juga akn tambahkan unit test yang lain pada fungsi-fungsi yang sudah kita buat sebelumnya seperti ini.
func TestSampleGetHandler(t *testing.T) {
tests := []struct {
name string
want string
}{
{
name: "test get",
want: "Hello Get",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
request := httptest.NewRequest(http.MethodGet, "http://localhost/", nil)
recorder := httptest.NewRecorder()
SampleGetHandler(recorder, request, nil)
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)
}
assert.Equal(t, tt.want, bodyString)
})
}
}
func TestSamplePostHandler(t *testing.T) {
tests := []struct {
name string
want string
}{
{
name: "test post",
want: "Hello Post",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "http://localhost/", nil)
recorder := httptest.NewRecorder()
SamplePostHandler(recorder, request, nil)
response := recorder.Result()
body, _ := io.ReadAll(response.Body)
bodyString := string(body)
assert.Equal(t, tt.want, bodyString)
})
}
}