Router mirip dengan ServeMux, dimana kita bisa menambahkan route ke dalam Router
Kelebihan dibandingkan dengan ServeMux adalah, pada Router, kita bisa menentukan HTTP Method yang ingin kita gunakan, misal GET, POST, PUT, dan lain-lain
Cara menambahkan route ke dalam Router adalah gunakan function yang sama dengan HTTP Method nya, misal router.GET(), router.POST(), dan lain-lain
httprouter.Handler
Saat kita menggunakan ServeMux, ketika menambah route, kita bisa menambahkan http.Handler
Berbeda dengan Router, pada Router kita tidak menggunakan http.Handler lagi, melainkan menggunakan type httprouter.Handle
Perbedaan dengan http.Handler adalah, pada httprouter.Handle, terdapat parameter ke tiga yaitu Params, yang akan kita bahas nanti di chapter tersendiri
// Handle is a function that can be registered to a route to handle HTTP requests.// Like http.HandlerFunc, but has a third parameter for the values of wildcards (variables).typeHandlefunc(http.ResponseWriter, *http.Request, Params)
httprouter.Handle memiliki parameter yang ketiga, yaitu Params. Untuk apa kegunaan Params?
Params merupakan tempat untuk menyimpan parameter yang dikirim dari client
Namun Params ini bukan query parameter, melainkan parameter di URL
Kadang kita butuh membuat URL yang tidak fix, alias bisa berubah-ubah, misal /products/1, /products/2, dan seterusnya
ServeMux tidak mendukung hal tersebut, namun Router mendukung hal tersebut
Parameter yang dinamis yang terdapat di URL, secara otomatis dikumpulkan di Params
Namun, agar Router tahu, kita harus memberi tahu ketika menambahkan Route, dibagian mana kita akan buat URL path nya menjadi dinamis
Kode: Params
funcTestRouterParams(t*testing.T) {
router:=httprouter.New()
router.GET("/products/:id", func(writer http.ResponseWriter, request*http.Request, params httprouter.Params) {
t.Log(params)
fmt.Fprintf(writer, "You requested a product with id %s", params.ByName("id"))
})
productId:="1"request:=httptest.NewRequest(http.MethodGet, "/products/"+productId, nil)
recorder:=httptest.NewRecorder()
router.ServeHTTP(recorder, request)
response:=recorder.Result()
responseBody, _:=ioutil.ReadAll(response.Body)
deferresponse.Body.Close()
assert.Equal(t, http.StatusOK, response.StatusCode, "response status code should be 200")
assert.Equal(t, "You requested a product with id "+productId, string(responseBody), "response body should be 'You requested a product with id 1'")
t.Log(string(responseBody))
}
Router Pattern
Sekarang kita sudah tahu bahwa dengan menggunakan Router, kita bisa menambah params di URL
Sekarang pertanyaannya, bagaimana pattern (pola) pembuatan parameter nya?
Named Parameter
Named parameter adalah pola pembuatan parameter dengan menggunakan nama
Setiap nama parameter harus diawali dengan : (titik dua), lalu diikuti dengan nama parameter
Contoh, jika kita memiliki pattern seperti ini :
Pattern
/user/:user
/user/eko
match
/user/you
match
/user/eko/profile
not match
/user/
not match
Catch All Parameter
Selain named parameter, ada juga yang bernama catch all parameter, yaitu menangkap semua parameter
Catch all parameter harus diawali dengan * (bintang), lalu diikuti dengan nama parameter
Catch all parameter harus berada di posisi akhir URL
Pada materi Go-Lang Web, kita sudah pernah membahas tentang Serve File
Pada Router pun, mendukung serve static file menggunakan function ServeFiles(Path, FileSystem)
Dimana pada Path, kita harus menggunakan Catch All Parameter
Sedangkan pada FileSystem kita bisa melakukan manual load dari folder atau menggunakan golang embed, seperti yang pernah kita bahas di materi Go-Lang Web
Kode: ServeFile
funcTestRouterServeFile(t*testing.T) {
router:=httprouter.New()
// create a dir destination so we don't need// to specify the file folder, i.e resourcesdir, _:=fs.Sub(resources, "resources")
// *filepath is hardcoded in ServeFile// so its must be named *filepathrouter.ServeFiles("/files/*filepath", http.FS(dir))
request:=httptest.NewRequest(http.MethodGet, "/files/test.txt", nil)
recorder:=httptest.NewRecorder()
router.ServeHTTP(recorder, request)
response:=recorder.Result()
assert.Equal(t, http.StatusOK, response.StatusCode)
responseBody, _:=ioutil.ReadAll(response.Body)
assert.Equal(t, "test", string(responseBody))
t.Log(string(responseBody))
}
Panic Handler
Apa yang terjadi jika terjadi panic pada logic Handler yang kita buat?
Secara otomatis akan terjadi error, dan web akan berhenti mengembalikan response
Kadang saat terjadi panic, kita ingin melakukan sesuatu, misal memberitahu jika terjadi kesalahan di web, atau bahkan mengirim informasi log kesalahan yang terjadi
Sebelumnya, seperti yang sudah kita bahas di materi Go-Lang Web, jika kita ingin menangani panic, kita harus membuat Middleware khusus secara manual
Namun di Router, sudah disediakan untuk menangani panic, caranya dengan menggunakan attribute
Saat menggunakan ServeMux, kita tidak bisa menentukan HTTP Method apa yang digunakan untuk Handler
Namun pada Router, kita bisa menentukan HTTP Method yang ingin kita gunakan, lantas apa yang terjadi jika client tidak mengirim HTTP Method sesuai dengan yang kita tentukan?
Maka akan terjadi error Method Not Allowed
Secara default, jika terjadi error seperti ini, maka Router akan memanggil function http.Error
Jika kita ingin mengubahnya, kita bisa gunakan router.MethodNotAllowed = http.Handler
HttpRouter hanyalah library untuk http router saja, tidak ada fitur lain selain router
Dan karena Router merupakan implementasi dari http.Handler, jadi untuk middleware, kita bisa membuat sendiri, seperti yang sudah kita bahas pada course Go-Lang Web