🎣 Hooks
With hooks, you can manipulate the client on before request/after response stages or more complex logging/tracing cases.
There are 2 kinds of hooks:
Request Hooks
They are called before the HTTP request has been sent. You can use them make changes on Request object.
You need to use RequestHook func(*Client, *Request) error
function signature while creating the hooks. You can use request hooks to change host URL, log request properties etc. Here is an example about how to create request hooks:
type Repository struct {
Name string `json:"name"`
FullName string `json:"full_name"`
Description string `json:"description"`
Homepage string `json:"homepage"`
Owner struct {
Login string `json:"login"`
} `json:"owner"`
}
func main() {
cc := client.New()
cc.AddRequestHook(func(c *client.Client, r *client.Request) error {
r.SetURL("https://api.github.com/" + r.URL())
return nil
})
resp, err := cc.Get("repos/gofiber/fiber")
if err != nil {
panic(err)
}
var repo Repository
if err := resp.JSON(&repo); err != nil {
panic(err)
}
fmt.Printf("Status code: %d\n", resp.StatusCode())
fmt.Printf("Repository: %s\n", repo.FullName)
fmt.Printf("Description: %s\n", repo.Description)
fmt.Printf("Homepage: %s\n", repo.Homepage)
fmt.Printf("Owner: %s\n", repo.Owner.Login)
fmt.Printf("Name: %s\n", repo.Name)
fmt.Printf("Full Name: %s\n", repo.FullName)
}
Click here to see the result
Status code: 200
Repository: gofiber/fiber
Description: ⚡️ Express inspired web framework written in Go
Homepage: https://gofiber.io
Owner: gofiber
Name: fiber
Full Name: gofiber/fiber
There are also some builtin request hooks provide some functionalities for Fiber client. Here is a list of them:
-
parserRequestURL: parserRequestURL customizes the URL according to the path params and query params. It's necessary for
PathParam
andQueryParam
methods. -
parserRequestHeader: parserRequestHeader sets request headers, cookies, body type, referer, user agent according to client and request properties. It's necessary to make request header and cookiejar methods functional.
-
parserRequestBody: parserRequestBody serializes the body automatically. It is useful for XML, JSON, form, file bodies.
If any error returns from request hook execution, it will interrupt the request and return the error.
func main() {
cc := client.New()
cc.AddRequestHook(func(c *client.Client, r *client.Request) error {
fmt.Println("Hook 1")
return errors.New("error")
})
cc.AddRequestHook(func(c *client.Client, r *client.Request) error {
fmt.Println("Hook 2")
return nil
})
_, err := cc.Get("https://example.com/")
if err != nil {
panic(err)
}
}
Click here to see the result
Hook 1.
panic: error
goroutine 1 [running]:
main.main()
main.go:25 +0xaa
exit status 2
Response Hooks
They are called after the HTTP response has been completed. You can use them to get some information about response and request.
You need to use ResponseHook func(*Client, *Response, *Request) error
function signature while creating the hooks. You can use response hook for logging, tracing etc. Here is an example about how to create response hooks:
func main() {
cc := client.New()
cc.AddResponseHook(func(c *client.Client, resp *client.Response, req *client.Request) error {
fmt.Printf("Response Status Code: %d\n", resp.StatusCode())
fmt.Printf("HTTP protocol: %s\n\n", resp.Protocol())
fmt.Println("Response Headers:")
resp.RawResponse.Header.VisitAll(func(key, value []byte) {
fmt.Printf("%s: %s\n", key, value)
})
return nil
})
_, err := cc.Get("https://example.com/")
if err != nil {
panic(err)
}
}
Click here to see the result
Response Status Code: 200
HTTP protocol: HTTP/1.1
Response Headers:
Content-Length: 1256
Content-Type: text/html; charset=UTF-8
Server: ECAcc (dcd/7D5A)
Age: 216114
Cache-Control: max-age=604800
Date: Fri, 10 May 2024 10:49:10 GMT
Etag: "3147526947+gzip+ident"
Expires: Fri, 17 May 2024 10:49:10 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Vary: Accept-Encoding
X-Cache: HIT
There are also some builtin request hooks provide some functionalities for Fiber client. Here is a list of them:
-
parserResponseCookie: parserResponseCookie parses cookies and saves into the response objects and cookiejar if it's exists.
-
logger: logger prints some RawRequest and RawResponse information. It uses log.CommonLogger interface for logging.
If any error is returned from executing the response hook, it will return the error without executing other response hooks.
func main() {
cc := client.New()
cc.AddResponseHook(func(c *client.Client, r1 *client.Response, r2 *client.Request) error {
fmt.Println("Hook 1")
return nil
})
cc.AddResponseHook(func(c *client.Client, r1 *client.Response, r2 *client.Request) error {
fmt.Println("Hook 2")
return errors.New("error")
})
cc.AddResponseHook(func(c *client.Client, r1 *client.Response, r2 *client.Request) error {
fmt.Println("Hook 3")
return nil
})
_, err := cc.Get("https://example.com/")
if err != nil {
panic(err)
}
}
Click here to see the result
Hook 1
Hook 2
panic: error
goroutine 1 [running]:
main.main()
main.go:30 +0xd6
exit status 2
Hooks work as FIFO (first-in-first-out). You need to check the order while adding the hooks.
func main() {
cc := client.New()
cc.AddRequestHook(func(c *client.Client, r *client.Request) error {
fmt.Println("Hook 1")
return nil
})
cc.AddRequestHook(func(c *client.Client, r *client.Request) error {
fmt.Println("Hook 2")
return nil
})
_, err := cc.Get("https://example.com/")
if err != nil {
panic(err)
}
}
Click here to see the result
Hook 1
Hook 2