From 0fa70ab211a416d681086b0ab8a2f4a3b86f01c0 Mon Sep 17 00:00:00 2001 From: ItsMeSamey <92444995+ItsMeSamey@users.noreply.github.com> Date: Fri, 18 Oct 2024 02:16:48 +0530 Subject: [PATCH 01/12] Fix nil pointer dereference with Must Bind binding error if err is nil err.Error() panics (eg. c.Bind().Must().JSON(...) successfully binds but panics --- bind.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bind.go b/bind.go index e202cd85e0..b66d0a3da2 100644 --- a/bind.go +++ b/bind.go @@ -41,7 +41,7 @@ func (b *Bind) Must() *Bind { // Check Should/Must errors and return it by usage. func (b *Bind) returnErr(err error) error { - if !b.should { + if !b.should && err != nil { b.ctx.Status(StatusBadRequest) return NewError(StatusBadRequest, "Bad request: "+err.Error()) } From 791f4bae86af51d91d0f3a9bc565671288688884 Mon Sep 17 00:00:00 2001 From: ItsMeSamey <92444995+ItsMeSamey@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:58:19 +0530 Subject: [PATCH 02/12] Added returnErr test make sure returnErr works with nil error --- bind_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bind_test.go b/bind_test.go index aa00e191ca..9cbb51c46c 100644 --- a/bind_test.go +++ b/bind_test.go @@ -19,6 +19,15 @@ import ( const helloWorld = "hello world" +// go test -run Test_returnErr -v +func Test_returnErr(t *testing.T) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + + err := c.Bind().Must().returnErr(nil) + require.Equal(t, nil, err) +} + // go test -run Test_Bind_Query -v func Test_Bind_Query(t *testing.T) { t.Parallel() From dde670f7204d840869c3c77c47faffc1b069fe47 Mon Sep 17 00:00:00 2001 From: ItsMeSamey <92444995+ItsMeSamey@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:00:30 +0530 Subject: [PATCH 03/12] Reordered returnErr nil check as in majority of cases we expect err to be nil, this should provide better short-cutting --- bind.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bind.go b/bind.go index b66d0a3da2..a55b91cb38 100644 --- a/bind.go +++ b/bind.go @@ -41,12 +41,12 @@ func (b *Bind) Must() *Bind { // Check Should/Must errors and return it by usage. func (b *Bind) returnErr(err error) error { - if !b.should && err != nil { - b.ctx.Status(StatusBadRequest) - return NewError(StatusBadRequest, "Bad request: "+err.Error()) + if err == nil || b.should { + return err } - return err + b.ctx.Status(StatusBadRequest) + return NewError(StatusBadRequest, "Bad request: "+err.Error()) } // Struct validation. From 94d08adcd049bef9705eef88923e0c2db39e7042 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Fri, 18 Oct 2024 08:37:47 -0400 Subject: [PATCH 04/12] Use require.NoError --- bind_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bind_test.go b/bind_test.go index 9cbb51c46c..4f4fb71ec6 100644 --- a/bind_test.go +++ b/bind_test.go @@ -25,7 +25,7 @@ func Test_returnErr(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) err := c.Bind().Must().returnErr(nil) - require.Equal(t, nil, err) + require.NoError(t, nil, err) } // go test -run Test_Bind_Query -v From b15eda0891646a072b1773a8003cfaeec116b7b0 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Fri, 18 Oct 2024 08:41:19 -0400 Subject: [PATCH 05/12] Update bind_test.go --- bind_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bind_test.go b/bind_test.go index 4f4fb71ec6..710c7aec8c 100644 --- a/bind_test.go +++ b/bind_test.go @@ -25,7 +25,7 @@ func Test_returnErr(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) err := c.Bind().Must().returnErr(nil) - require.NoError(t, nil, err) + require.NoError(t, err) } // go test -run Test_Bind_Query -v From 45eb05affb32477361eab65aa8ea4fb38e367073 Mon Sep 17 00:00:00 2001 From: ItsMeSamey Date: Sat, 16 Nov 2024 13:18:20 +0530 Subject: [PATCH 06/12] Renamed Must to WithAutoHandling --- bind.go | 10 +++++----- bind_test.go | 8 ++++---- binder/README.md | 6 +++--- docs/api/bind.md | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bind.go b/bind.go index a55b91cb38..dabff278c9 100644 --- a/bind.go +++ b/bind.go @@ -31,15 +31,15 @@ func (b *Bind) Should() *Bind { return b } -// Must If you want to handle binder errors automatically, you can use Must. +// If you want to handle binder errors automatically, you can use WithAutoHandling. // If there's an error it'll return error and 400 as HTTP status. -func (b *Bind) Must() *Bind { +func (b *Bind) WithAutoHandling() *Bind { b.should = false return b } -// Check Should/Must errors and return it by usage. +// Check Should/WithAutoHandling errors and return it by usage. func (b *Bind) returnErr(err error) error { if err == nil || b.should { return err @@ -62,7 +62,7 @@ func (b *Bind) validateStruct(out any) error { // Custom To use custom binders, you have to use this method. // You can register them from RegisterCustomBinder method of Fiber instance. // They're checked by name, if it's not found, it will return an error. -// NOTE: Should/Must is still valid for Custom binders. +// NOTE: Should/WithAutoHandling is still valid for Custom binders. func (b *Bind) Custom(name string, dest any) error { binders := b.ctx.App().customBinders for _, customBinder := range binders { @@ -92,7 +92,7 @@ func (b *Bind) RespHeader(out any) error { return b.validateStruct(out) } -// Cookie binds the requesr cookie strings into the struct, map[string]string and map[string][]string. +// Cookie binds the request cookie strings into the struct, map[string]string and map[string][]string. // NOTE: If your cookie is like key=val1,val2; they'll be binded as an slice if your map is map[string][]string. Else, it'll use last element of cookie. func (b *Bind) Cookie(out any) error { if err := b.returnErr(binder.CookieBinder.Bind(b.ctx.Context(), out)); err != nil { diff --git a/bind_test.go b/bind_test.go index 710c7aec8c..a75722b3b4 100644 --- a/bind_test.go +++ b/bind_test.go @@ -24,7 +24,7 @@ func Test_returnErr(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - err := c.Bind().Must().returnErr(nil) + err := c.Bind().WithAutoHandling().returnErr(nil) require.NoError(t, err) } @@ -1625,8 +1625,8 @@ func Test_Bind_CustomBinder(t *testing.T) { require.Equal(t, "john", d.Name) } -// go test -run Test_Bind_Must -func Test_Bind_Must(t *testing.T) { +// go test -run Test_Bind_WithAutoHandling +func Test_Bind_WithAutoHandling(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) @@ -1635,7 +1635,7 @@ func Test_Bind_Must(t *testing.T) { } rq := new(RequiredQuery) c.Request().URI().SetQueryString("") - err := c.Bind().Must().Query(rq) + err := c.Bind().WithAutoHandling().Query(rq) require.Equal(t, StatusBadRequest, c.Response().StatusCode()) require.Equal(t, "Bad request: bind: name is empty", err.Error()) } diff --git a/binder/README.md b/binder/README.md index 676e1c9e89..8a42f981e5 100644 --- a/binder/README.md +++ b/binder/README.md @@ -83,9 +83,9 @@ app.Get("/", func(c fiber.Ctx) error { // curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" ``` -### Behaviors of Should/Must +### Behaviors of Should/WithAutoHandling -Normally, Fiber returns binder error directly. However; if you want to handle it automatically, you can prefer `Must()`. +Normally, Fiber returns binder error directly. However; if you want to handle it automatically, you can prefer `WithAutoHandling()`. If there's an error it'll return error and 400 as HTTP status. Here's an example for it: @@ -99,7 +99,7 @@ type Person struct { app.Get("/", func(c fiber.Ctx) error { p := new(Person) - if err := c.Bind().Must().JSON(p); err != nil { + if err := c.Bind().WithAutoHandling().JSON(p); err != nil { return err // Status code: 400 // Response: Bad request: name is empty diff --git a/docs/api/bind.md b/docs/api/bind.md index 73256cbbb8..20bd1b9461 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -439,13 +439,13 @@ For this the MIMETypes method is used to check if the custom binder should be us For more control over the error handling, you can use the following methods. -### Must +### WithAutoHandling -If you want to handle binder errors automatically, you can use Must. +If you want to handle binder errors automatically, you can use WithAutoHandling. If there's an error it'll return error and 400 as HTTP status. ```go title="Signature" -func (b *Bind) Must() *Bind +func (b *Bind) WithAutoHandling() *Bind ``` ### Should From 0cfa1c897bf38bb2f7e29069f7370a0f115e1773 Mon Sep 17 00:00:00 2001 From: ItsMeSamey <92444995+ItsMeSamey@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:07:36 +0530 Subject: [PATCH 07/12] Update bind.md Added a requested clarification --- docs/api/bind.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/bind.md b/docs/api/bind.md index dac0578450..877600e83d 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -462,6 +462,7 @@ For more control over error handling, you can use the following methods. If you want to handle binder errors automatically, you can use `WithAutoHandling`. If there's an error, it will return the error and set HTTP status to `400 Bad Request`. +This function does NOT panic therefor you must still return on error explicitly ```go title="Signature" func (b *Bind) WithAutoHandling() *Bind From 8ec94277f3394438e6354e64e21b188a11aa51a9 Mon Sep 17 00:00:00 2001 From: ItsMeSamey Date: Thu, 21 Nov 2024 17:25:59 +0530 Subject: [PATCH 08/12] renamed Should to WithoutAutoHandling and Bind.should to Bind.dontHandle --- bind.go | 23 ++++++++++++----------- binder/README.md | 2 +- ctx.go | 8 ++++---- docs/api/bind.md | 6 +++--- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/bind.go b/bind.go index ef0f349be7..03bca4662b 100644 --- a/bind.go +++ b/bind.go @@ -19,29 +19,30 @@ type StructValidator interface { // Bind struct type Bind struct { - ctx Ctx - should bool + ctx Ctx + dontHandle bool } -// Should To handle binder errors manually, you can prefer Should method. +// If you want to handle binder errors manually, you can use `WithoutAutoHandling`. // It's default behavior of binder. -func (b *Bind) Should() *Bind { - b.should = true +func (b *Bind) WithoutAutoHandling() *Bind { + b.dontHandle = true return b } -// If you want to handle binder errors automatically, you can use WithAutoHandling. -// If there's an error it'll return error and 400 as HTTP status. +// If you want to handle binder errors automatically, you can use `WithAutoHandling`. +// If there's an error, it will return the error and set HTTP status to `400 Bad Request`. +// You must still return on error explicitly func (b *Bind) WithAutoHandling() *Bind { - b.should = false + b.dontHandle = false return b } -// Check Should/WithAutoHandling errors and return it by usage. +// Check WithAutoHandling/WithoutAutoHandling errors and return it by usage. func (b *Bind) returnErr(err error) error { - if err == nil || b.should { + if err == nil || b.dontHandle { return err } @@ -62,7 +63,7 @@ func (b *Bind) validateStruct(out any) error { // Custom To use custom binders, you have to use this method. // You can register them from RegisterCustomBinder method of Fiber instance. // They're checked by name, if it's not found, it will return an error. -// NOTE: Should/WithAutoHandling is still valid for Custom binders. +// NOTE: WithAutoHandling/WithAutoHandling is still valid for Custom binders. func (b *Bind) Custom(name string, dest any) error { binders := b.ctx.App().customBinders for _, customBinder := range binders { diff --git a/binder/README.md b/binder/README.md index 8a42f981e5..f317f8b3a3 100644 --- a/binder/README.md +++ b/binder/README.md @@ -83,7 +83,7 @@ app.Get("/", func(c fiber.Ctx) error { // curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" ``` -### Behaviors of Should/WithAutoHandling +### Behaviors of WithAutoHandling/WithAutoHandlingWithStatus Normally, Fiber returns binder error directly. However; if you want to handle it automatically, you can prefer `WithAutoHandling()`. diff --git a/ctx.go b/ctx.go index a2eee2754b..48c70f28f8 100644 --- a/ctx.go +++ b/ctx.go @@ -640,7 +640,7 @@ func (c *DefaultCtx) Get(key string, defaultValue ...string) string { } // GetReqHeader returns the HTTP request header specified by filed. -// This function is generic and can handle differnet headers type values. +// This function is generic and can handle different headers type values. func GetReqHeader[V GenericType](c Ctx, key string, defaultValue ...V) V { var v V return genericParseType[V](c.App().getString(c.Request().Header.Peek(key)), v, defaultValue...) @@ -1083,7 +1083,7 @@ func (c *DefaultCtx) Params(key string, defaultValue ...string) string { } // Params is used to get the route parameters. -// This function is generic and can handle differnet route parameters type values. +// This function is generic and can handle different route parameters type values. // // Example: // @@ -1860,8 +1860,8 @@ func (c *DefaultCtx) IsFromLocal() bool { func (c *DefaultCtx) Bind() *Bind { if c.bind == nil { c.bind = &Bind{ - ctx: c, - should: true, + ctx : c, + dontHandle: true, } } return c.bind diff --git a/docs/api/bind.md b/docs/api/bind.md index 877600e83d..a1cbedd18d 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -468,13 +468,13 @@ This function does NOT panic therefor you must still return on error explicitly func (b *Bind) WithAutoHandling() *Bind ``` -### Should +### WithoutAutoHandling -To handle binder errors manually, you can use the `Should` method. +To handle binder errors manually, you can use the `WithoutAutoHandling` method. It's the default behavior of the binder. ```go title="Signature" -func (b *Bind) Should() *Bind +func (b *Bind) WithoutAutoHandling() *Bind ``` ## SetParserDecoder From 56973394a7692e2ad0fcf42d4fee0ddec0229330 Mon Sep 17 00:00:00 2001 From: ItsMeSamey Date: Fri, 22 Nov 2024 01:05:22 +0530 Subject: [PATCH 09/12] renamed dontHandle to dontHandleErrs --- bind.go | 8 ++++---- ctx.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bind.go b/bind.go index 03bca4662b..2b434ad830 100644 --- a/bind.go +++ b/bind.go @@ -20,13 +20,13 @@ type StructValidator interface { // Bind struct type Bind struct { ctx Ctx - dontHandle bool + dontHandleErrs bool } // If you want to handle binder errors manually, you can use `WithoutAutoHandling`. // It's default behavior of binder. func (b *Bind) WithoutAutoHandling() *Bind { - b.dontHandle = true + b.dontHandleErrs = true return b } @@ -35,14 +35,14 @@ func (b *Bind) WithoutAutoHandling() *Bind { // If there's an error, it will return the error and set HTTP status to `400 Bad Request`. // You must still return on error explicitly func (b *Bind) WithAutoHandling() *Bind { - b.dontHandle = false + b.dontHandleErrs = false return b } // Check WithAutoHandling/WithoutAutoHandling errors and return it by usage. func (b *Bind) returnErr(err error) error { - if err == nil || b.dontHandle { + if err == nil || b.dontHandleErrs { return err } diff --git a/ctx.go b/ctx.go index 48c70f28f8..42d05d50c9 100644 --- a/ctx.go +++ b/ctx.go @@ -1861,7 +1861,7 @@ func (c *DefaultCtx) Bind() *Bind { if c.bind == nil { c.bind = &Bind{ ctx : c, - dontHandle: true, + dontHandleErrs: true, } } return c.bind From 0b6b0353c752f83ff6a1de60f1c251dedf702b82 Mon Sep 17 00:00:00 2001 From: ItsMeSamey Date: Fri, 22 Nov 2024 16:34:50 +0530 Subject: [PATCH 10/12] fixed formatting --- bind.go | 4 ++-- ctx.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bind.go b/bind.go index 2b434ad830..ad76594265 100644 --- a/bind.go +++ b/bind.go @@ -19,7 +19,7 @@ type StructValidator interface { // Bind struct type Bind struct { - ctx Ctx + ctx Ctx dontHandleErrs bool } @@ -31,7 +31,7 @@ func (b *Bind) WithoutAutoHandling() *Bind { return b } -// If you want to handle binder errors automatically, you can use `WithAutoHandling`. +// If you want to handle binder errors automatically, you can use `WithAutoHandling`. // If there's an error, it will return the error and set HTTP status to `400 Bad Request`. // You must still return on error explicitly func (b *Bind) WithAutoHandling() *Bind { diff --git a/ctx.go b/ctx.go index 42d05d50c9..14fb7246b0 100644 --- a/ctx.go +++ b/ctx.go @@ -1860,7 +1860,7 @@ func (c *DefaultCtx) IsFromLocal() bool { func (c *DefaultCtx) Bind() *Bind { if c.bind == nil { c.bind = &Bind{ - ctx : c, + ctx: c, dontHandleErrs: true, } } From 6e667d657154bb9d158bab44dca1023537a18f13 Mon Sep 17 00:00:00 2001 From: ItsMeSamey Date: Fri, 22 Nov 2024 16:42:10 +0530 Subject: [PATCH 11/12] fixed a typo --- binder/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/README.md b/binder/README.md index f317f8b3a3..4b4613f77f 100644 --- a/binder/README.md +++ b/binder/README.md @@ -83,7 +83,7 @@ app.Get("/", func(c fiber.Ctx) error { // curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" ``` -### Behaviors of WithAutoHandling/WithAutoHandlingWithStatus +### Behaviors of WithAutoHandling/WithoutAutoHandling Normally, Fiber returns binder error directly. However; if you want to handle it automatically, you can prefer `WithAutoHandling()`. From 2a978980e3db17f01fd8bc8ac630cccb1c3655c4 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:47:24 -0500 Subject: [PATCH 12/12] Update binder documentation --- binder/README.md | 118 ++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 52 deletions(-) diff --git a/binder/README.md b/binder/README.md index 4b4613f77f..6794a3b93b 100644 --- a/binder/README.md +++ b/binder/README.md @@ -1,17 +1,19 @@ # Fiber Binders -Binder is a new request/response binding feature for Fiber. Against the old Fiber parsers, it supports custom binder registration, struct validation, `map[string]string`, `map[string][]string`, and more. It's introduced in Fiber v3 and a replacement of: +**Binder** is a new request/response binding feature for Fiber introduced in Fiber v3. It replaces the old Fiber parsers and offers enhanced capabilities such as custom binder registration, struct validation, support for `map[string]string`, `map[string][]string`, and more. Binder replaces the following components: -- BodyParser -- ParamsParser -- GetReqHeaders -- GetRespHeaders -- AllParams -- QueryParser -- ReqHeaderParser +- `BodyParser` +- `ParamsParser` +- `GetReqHeaders` +- `GetRespHeaders` +- `AllParams` +- `QueryParser` +- `ReqHeaderParser` ## Default Binders +Fiber provides several default binders out of the box: + - [Form](form.go) - [Query](query.go) - [URI](uri.go) @@ -23,12 +25,12 @@ Binder is a new request/response binding feature for Fiber. Against the old Fibe ## Guides -### Binding into the Struct +### Binding into a Struct -Fiber supports binding into the struct with [gorilla/schema](https://github.com/gorilla/schema). Here's an example: +Fiber supports binding request data directly into a struct using [gorilla/schema](https://github.com/gorilla/schema). Here's an example: ```go -// Field names should start with an uppercase letter +// Field names must start with an uppercase letter type Person struct { Name string `json:"name" xml:"name" form:"name"` Pass string `json:"pass" xml:"pass" form:"pass"` @@ -41,56 +43,63 @@ app.Post("/", func(c fiber.Ctx) error { return err } - log.Println(p.Name) // john - log.Println(p.Pass) // doe + log.Println(p.Name) // Output: john + log.Println(p.Pass) // Output: doe - // ... + // Additional logic... }) // Run tests with the following curl commands: -// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000 +// JSON +curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000 -// curl -X POST -H "Content-Type: application/xml" --data "johndoe" localhost:3000 +// XML +curl -X POST -H "Content-Type: application/xml" --data "johndoe" localhost:3000 -// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000 +// URL-Encoded Form +curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000 -// curl -X POST -F name=john -F pass=doe http://localhost:3000 +// Multipart Form +curl -X POST -F name=john -F pass=doe http://localhost:3000 -// curl -X POST "http://localhost:3000/?name=john&pass=doe" +// Query Parameters +curl -X POST "http://localhost:3000/?name=john&pass=doe" ``` -### Binding into the Map +### Binding into a Map -Fiber supports binding into the `map[string]string` or `map[string][]string`. Here's an example: +Fiber allows binding request data into a `map[string]string` or `map[string][]string`. Here's an example: ```go app.Get("/", func(c fiber.Ctx) error { - p := make(map[string][]string) + params := make(map[string][]string) - if err := c.Bind().Query(p); err != nil { + if err := c.Bind().Query(params); err != nil { return err } - log.Println(p["name"]) // john - log.Println(p["pass"]) // doe - log.Println(p["products"]) // [shoe, hat] + log.Println(params["name"]) // Output: [john] + log.Println(params["pass"]) // Output: [doe] + log.Println(params["products"]) // Output: [shoe hat] - // ... + // Additional logic... + return nil }) + // Run tests with the following curl command: -// curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" +curl "http://localhost:3000/?name=john&pass=doe&products=shoe&products=hat" ``` -### Behaviors of WithAutoHandling/WithoutAutoHandling +### Automatic Error Handling with `WithAutoHandling` -Normally, Fiber returns binder error directly. However; if you want to handle it automatically, you can prefer `WithAutoHandling()`. +By default, Fiber returns binder errors directly. To handle errors automatically and return a `400 Bad Request` status, use the `WithAutoHandling()` method. -If there's an error it'll return error and 400 as HTTP status. Here's an example for it: +**Example:** ```go -// Field names should start with an uppercase letter +// Field names must start with an uppercase letter type Person struct { Name string `json:"name,required"` Pass string `json:"pass"` @@ -101,21 +110,22 @@ app.Get("/", func(c fiber.Ctx) error { if err := c.Bind().WithAutoHandling().JSON(p); err != nil { return err - // Status code: 400 + // Automatically returns status code 400 // Response: Bad request: name is empty } - // ... + // Additional logic... + return nil }) // Run tests with the following curl command: -// curl -X GET -H "Content-Type: application/json" --data "{\"pass\":\"doe\"}" localhost:3000 +curl -X GET -H "Content-Type: application/json" --data "{\"pass\":\"doe\"}" localhost:3000 ``` -### Defining Custom Binder +### Defining a Custom Binder -We didn't add much binder to make Fiber codebase minimal. If you want to use your own binders, it's easy to register and use them. Here's an example for TOML binder. +Fiber maintains a minimal codebase by not including every possible binder. If you need to use a custom binder, you can easily register and utilize it. Here's an example of creating a `toml` binder. ```go type Person struct { @@ -147,24 +157,26 @@ func main() { return err } - // or you can use like: + // Alternatively, specify the custom binder: // if err := c.Bind().Custom("toml", out); err != nil { - // return err + // return err // } - return c.SendString(out.Pass) // test + return c.SendString(out.Pass) // Output: test }) app.Listen(":3000") } -// curl -X GET -H "Content-Type: application/toml" --data "name = 'bar' -// pass = 'test'" localhost:3000 +// Run tests with the following curl command: + +curl -X GET -H "Content-Type: application/toml" --data "name = 'bar' +pass = 'test'" localhost:3000 ``` -### Defining Custom Validator +### Defining a Custom Validator -All Fiber binders supporting struct validation if you defined validator inside of the config. You can create own validator, or use [go-playground/validator](https://github.com/go-playground/validator), [go-ozzo/ozzo-validation](https://github.com/go-ozzo/ozzo-validation)... Here's an example of simple custom validator: +All Fiber binders support struct validation if a validator is defined in the configuration. You can create your own validator or use existing ones like [go-playground/validator](https://github.com/go-playground/validator) or [go-ozzo/ozzo-validation](https://github.com/go-ozzo/ozzo-validation). Here's an example of a simple custom validator: ```go type Query struct { @@ -174,27 +186,29 @@ type Query struct { type structValidator struct{} func (v *structValidator) Engine() any { - return "" + return nil // Implement if using an external validation engine } func (v *structValidator) ValidateStruct(out any) error { - out = reflect.ValueOf(out).Elem().Interface() - sq := out.(Query) + data := reflect.ValueOf(out).Elem().Interface() + query := data.(Query) - if sq.Name != "john" { - return errors.New("you should have entered right name!") + if query.Name != "john" { + return errors.New("you should have entered the correct name!") } return nil } func main() { - app := fiber.New(fiber.Config{StructValidator: &structValidator{}}) + app := fiber.New(fiber.Config{ + StructValidator: &structValidator{}, + }) app.Get("/", func(c fiber.Ctx) error { out := new(Query) if err := c.Bind().Query(out); err != nil { - return err // you should have entered right name! + return err // Returns: you should have entered the correct name! } return c.SendString(out.Name) }) @@ -204,5 +218,5 @@ func main() { // Run tests with the following curl command: -// curl "http://localhost:3000/?name=efe" +curl "http://localhost:3000/?name=efe" ```