From dc10e5b9eef5ff82a83c8a5999bf62a85310750d Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 6 Jul 2024 02:54:24 -0400 Subject: [PATCH 01/13] Add support for consistent documentation using markdownlint --- .github/workflows/markdown.yml | 19 ++ .markdownlint.yml | 248 ++++++++++++++++ Makefile | 5 + addon/retry/README.md | 36 +-- binder/README.md | 140 +++++---- docs/api/app.md | 53 ++-- docs/api/bind.md | 23 +- docs/api/constants.md | 486 +++++++++++++++---------------- docs/api/ctx.md | 90 +++--- docs/api/fiber.md | 3 - docs/api/hooks.md | 72 ++--- docs/api/log.md | 20 +- docs/api/redirect.md | 1 - docs/client/examples.md | 214 +++++++------- docs/client/hooks.md | 190 ++++++------ docs/client/request.md | 102 +++---- docs/client/response.md | 34 +-- docs/client/rest.md | 136 ++++----- docs/extra/faq.md | 122 ++++---- docs/guide/error-handling.md | 1 + docs/guide/faster-fiber.md | 12 +- docs/guide/routing.md | 86 +++--- docs/guide/templates.md | 5 +- docs/guide/utils.md | 1 - docs/intro.md | 48 +-- docs/middleware/adaptor.md | 122 ++++---- docs/middleware/cache.md | 2 +- docs/middleware/cors.md | 40 +-- docs/middleware/csrf.md | 165 ++++++----- docs/middleware/earlydata.md | 30 +- docs/middleware/encryptcookie.md | 27 +- docs/middleware/envvar.md | 15 +- docs/middleware/expvar.md | 1 + docs/middleware/favicon.md | 8 +- docs/middleware/healthcheck.md | 26 +- docs/middleware/helmet.md | 23 +- docs/middleware/idempotency.md | 40 +-- docs/middleware/keyauth.md | 200 ++++++------- docs/middleware/limiter.md | 10 +- docs/middleware/logger.md | 6 +- docs/middleware/monitor.md | 59 ++-- docs/middleware/proxy.md | 3 +- docs/middleware/redirect.md | 2 +- docs/middleware/requestid.md | 3 +- docs/middleware/rewrite.md | 1 + docs/middleware/session.md | 30 +- docs/middleware/skip.md | 21 +- docs/middleware/static.md | 1 + docs/middleware/timeout.md | 135 +++++---- docs/whats_new.md | 97 +++--- middleware/adaptor/README.md | 120 ++++---- middleware/helmet/README.md | 37 ++- middleware/keyauth/README.md | 51 ++-- 53 files changed, 1878 insertions(+), 1544 deletions(-) create mode 100644 .github/workflows/markdown.yml create mode 100644 .markdownlint.yml diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml new file mode 100644 index 0000000000..544bd7c871 --- /dev/null +++ b/.github/workflows/markdown.yml @@ -0,0 +1,19 @@ +name: markdownlint +on: + push: + branches: + - master + - main + pull_request: + +jobs: + markdownlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: DavidAnson/markdownlint-cli2-action@v16 + with: + globs: | + **/*.md + !.github diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 0000000000..bc3d88cfb7 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,248 @@ +# Example markdownlint configuration with all properties set to their default value + +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD001/heading-increment : Heading levels should only increment by one level at a time : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md001.md +MD001: true + +# MD003/heading-style : Heading style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md003.md +MD003: + # Heading style + style: "consistent" + +# MD004/ul-style : Unordered list style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md004.md +MD004: + # List style + style: "consistent" + +# MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md005.md +MD005: true + +# MD007/ul-indent : Unordered list indentation : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md007.md +MD007: + # Spaces for indent + indent: + # Whether to indent the first level of the list + start_indented: false + # Spaces for first level indent (when start_indented is set) + start_indent: 2 + +# MD009/no-trailing-spaces : Trailing spaces : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md009.md +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: true + +# MD010/no-hard-tabs : Hard tabs : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md010.md +MD010: + # Include code blocks + code_blocks: true + # Fenced code languages to ignore + ignore_code_languages: [] + # Number of spaces for each hard tab + spaces_per_tab: 4 + +# MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md011.md +MD011: true + +# MD012/no-multiple-blanks : Multiple consecutive blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md012.md +MD012: + # Consecutive blank lines + maximum: 1 + +# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md013.md +MD013: false + +# MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md014.md +MD014: true + +# MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md018.md +MD018: true + +# MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md019.md +MD019: true + +# MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md020.md +MD020: true + +# MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md021.md +MD021: true + +# MD022/blanks-around-headings : Headings should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md022.md +MD022: + # Blank lines above heading + lines_above: 1 + # Blank lines below heading + lines_below: 1 + +# MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md023.md +MD023: true + +# MD024/no-duplicate-heading : Multiple headings with the same content : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md024.md +MD024: false + +# MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md025.md +MD025: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD026/no-trailing-punctuation : Trailing punctuation in heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md026.md +MD026: + # Punctuation characters + punctuation: ".,;:!。,;:!" + +# MD027/no-multiple-space-blockquote : Multiple spaces after blockquote symbol : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md027.md +MD027: true + +# MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md028.md +MD028: true + +# MD029/ol-prefix : Ordered list item prefix : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md029.md +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space : Spaces after list markers : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md030.md +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD031/blanks-around-fences : Fenced code blocks should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md031.md +MD031: + # Include list items + list_items: true + +# MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md032.md +MD032: true + +# MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md033.md +MD033: false + +# MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md034.md +MD034: true + +# MD035/hr-style : Horizontal rule style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md035.md +MD035: + # Horizontal rule style + style: "consistent" + +# MD036/no-emphasis-as-heading : Emphasis used instead of a heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md036.md +MD036: + # Punctuation characters + punctuation: ".,;:!?。,;:!?" + +# MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md037.md +MD037: true + +# MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md038.md +MD038: true + +# MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md039.md +MD039: true + +# MD040/fenced-code-language : Fenced code blocks should have a language specified : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md040.md +MD040: + # List of languages + allowed_languages: [] + # Require language only + language_only: false + +# MD041/first-line-heading/first-line-h1 : First line in a file should be a top-level heading : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md041.md +MD041: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md042.md +MD042: true + +# MD043/required-headings : Required heading structure : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md043.md +MD043: false + +# MD044/proper-names : Proper names should have the correct capitalization : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md044.md +MD044: + # List of proper names + names: [] + # Include code blocks + code_blocks: true + # Include HTML elements + html_elements: true + +# MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md045.md +MD045: false + +# MD046/code-block-style : Code block style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md046.md +MD046: + # Block style + style: "fenced" + +# MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md047.md +MD047: true + +# MD048/code-fence-style : Code fence style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md048.md +MD048: + # Code fence style + style: "backtick" + +# MD049/emphasis-style : Emphasis style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md049.md +MD049: + # Emphasis style + style: "consistent" + +# MD050/strong-style : Strong style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md050.md +MD050: + # Strong style + style: "consistent" + +# MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md051.md +MD051: true + +# MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md052.md +MD052: + # Include shortcut syntax + shortcut_syntax: false + +# MD053/link-image-reference-definitions : Link and image reference definitions should be needed : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md053.md +MD053: + # Ignored definitions + ignored_definitions: + - "//" + +# MD054/link-image-style : Link and image style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md054.md +MD054: + # Allow autolinks + autolink: true + # Allow inline links and images + inline: true + # Allow full reference links and images + full: true + # Allow collapsed reference links and images + collapsed: true + # Allow shortcut reference links and images + shortcut: true + # Allow URLs as inline links + url_inline: true + +# MD055/table-pipe-style : Table pipe style : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md055.md +MD055: + # Table pipe style + style: "consistent" + +# MD056/table-column-count : Table column count : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md056.md +MD056: true diff --git a/Makefile b/Makefile index 0d4be85fa4..0b0008d278 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,11 @@ coverage: format: go run mvdan.cc/gofumpt@latest -w -l . +## format: 🎨 Find markdown format issues (Requires markdownlint-cli) +.PHONY: markdown +format: + markdownlint-cli2 "**/*.md" "#.github" + ## lint: 🚨 Run lint checks .PHONY: lint lint: diff --git a/addon/retry/README.md b/addon/retry/README.md index a07c7637e5..0ea963b985 100644 --- a/addon/retry/README.md +++ b/addon/retry/README.md @@ -3,18 +3,18 @@ Retry addon for [Fiber](https://github.com/gofiber/fiber) designed to apply retry mechanism for unsuccessful network operations. This addon uses exponential backoff algorithm with jitter. It calls the function multiple times and tries to make it successful. If all calls are failed, then, it returns error. It adds a jitter at each retry step because adding -a jitter is a way to break synchronization across the client and avoid collision. +a jitter is a way to break synchronization across the client and avoid collision. ## Table of Contents - [Retry Addon](#retry-addon) - - [Table of Contents](#table-of-contents) - - [Signatures](#signatures) - - [Examples](#examples) - - [Default Config](#default-config) - - [Custom Config](#custom-config) - - [Config](#config) - - [Default Config Example](#default-config-example) +- [Table of Contents](#table-of-contents) +- [Signatures](#signatures) +- [Examples](#examples) +- [Default Config](#default-config) +- [Custom Config](#custom-config) +- [Config](#config) +- [Default Config Example](#default-config-example) ## Signatures @@ -42,10 +42,10 @@ retry.NewExponentialBackoff() ```go retry.NewExponentialBackoff(retry.Config{ - InitialInterval: 2 * time.Second, - MaxBackoffTime: 64 * time.Second, - Multiplier: 2.0, - MaxRetryCount: 15, + InitialInterval: 2 * time.Second, + MaxBackoffTime: 64 * time.Second, + Multiplier: 2.0, + MaxRetryCount: 15, }) ``` @@ -88,10 +88,10 @@ type Config struct { ```go // DefaultConfig is the default config for retry. var DefaultConfig = Config{ - InitialInterval: 1 * time.Second, - MaxBackoffTime: 32 * time.Second, - Multiplier: 2.0, - MaxRetryCount: 10, - currentInterval: 1 * time.Second, + InitialInterval: 1 * time.Second, + MaxBackoffTime: 32 * time.Second, + Multiplier: 2.0, + MaxRetryCount: 10, + currentInterval: 1 * time.Second, } -``` \ No newline at end of file +``` diff --git a/binder/README.md b/binder/README.md index d40cc7e54e..b1b846b736 100644 --- a/binder/README.md +++ b/binder/README.md @@ -1,6 +1,7 @@ # Fiber Binders -Binder is new request/response binding feature for Fiber. By aganist 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 new request/response binding feature for Fiber. By aganist 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: + - BodyParser - ParamsParser - GetReqHeaders @@ -9,8 +10,8 @@ Binder is new request/response binding feature for Fiber. By aganist old Fiber p - QueryParser - ReqHeaderParser - ## Default Binders + - [Form](form.go) - [Query](query.go) - [URI](uri.go) @@ -23,7 +24,9 @@ Binder is new request/response binding feature for Fiber. By aganist old Fiber p ## Guides ### Binding into the Struct + Fiber supports binding into the struct with [gorilla/schema](https://github.com/gorilla/schema). Here's an example for it: + ```go // Field names should start with an uppercase letter type Person struct { @@ -32,16 +35,16 @@ type Person struct { } app.Post("/", func(c fiber.Ctx) error { - p := new(Person) + p := new(Person) - if err := c.Bind().Body(p); err != nil { - return err - } + if err := c.Bind().Body(p); err != nil { + return err + } - log.Println(p.Name) // john - log.Println(p.Pass) // doe + log.Println(p.Name) // john + log.Println(p.Pass) // doe - // ... + // ... }) // Run tests with the following curl commands: @@ -58,29 +61,34 @@ app.Post("/", func(c fiber.Ctx) error { ``` ### Binding into the Map -Fiber supports binding into the **map[string]string** or **map[string][]string**. Here's an example for it: + +Fiber supports binding into the `map[string]string` or `map[string][]string`. Here's an example for it: + ```go app.Get("/", func(c fiber.Ctx) error { - p := make(map[string][]string) + p := make(map[string][]string) - if err := c.Bind().Query(p); err != nil { - return err - } + if err := c.Bind().Query(p); err != nil { + return err + } - log.Println(p["name"]) // john - log.Println(p["pass"]) // doe - log.Println(p["products"]) // [shoe, hat] + log.Println(p["name"]) // john + log.Println(p["pass"]) // doe + log.Println(p["products"]) // [shoe, hat] - // ... + // ... }) // Run tests with the following curl command: // curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" ``` + ### Behaviors of Should/Must -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 `Must()`. If there's an error it'll return error and 400 as HTTP status. Here's an example for it: + ```go // Field names should start with an uppercase letter type Person struct { @@ -89,106 +97,112 @@ type Person struct { } app.Get("/", func(c fiber.Ctx) error { - p := new(Person) + p := new(Person) - if err := c.Bind().Must().JSON(p); err != nil { - return err - // Status code: 400 - // Response: Bad request: name is empty - } + if err := c.Bind().Must().JSON(p); err != nil { + return err + // Status code: 400 + // Response: Bad request: name is empty + } - // ... + // ... }) // Run tests with the following curl command: // curl -X GET -H "Content-Type: application/json" --data "{\"pass\":\"doe\"}" localhost:3000 ``` + ### Defining Custom Binder + We didn't add much binder to make Fiber codebase minimal. But if you want to use your binders, it's easy to register and use them. Here's an example for TOML binder. + ```go type Person struct { - Name string `toml:"name"` - Pass string `toml:"pass"` + Name string `toml:"name"` + Pass string `toml:"pass"` } type tomlBinding struct{} func (b *tomlBinding) Name() string { - return "toml" + return "toml" } func (b *tomlBinding) MIMETypes() []string { - return []string{"application/toml"} + return []string{"application/toml"} } func (b *tomlBinding) Parse(c fiber.Ctx, out any) error { - return toml.Unmarshal(c.Body(), out) + return toml.Unmarshal(c.Body(), out) } func main() { - app := fiber.New() - app.RegisterCustomBinder(&tomlBinding{}) + app := fiber.New() + app.RegisterCustomBinder(&tomlBinding{}) - app.Get("/", func(c fiber.Ctx) error { - out := new(Person) - if err := c.Bind().Body(out); err != nil { - return err - } + app.Get("/", func(c fiber.Ctx) error { + out := new(Person) + if err := c.Bind().Body(out); err != nil { + return err + } - // or you can use like: - // if err := c.Bind().Custom("toml", out); err != nil { - // return err - // } + // or you can use like: + // if err := c.Bind().Custom("toml", out); err != nil { + // return err + // } - return c.SendString(out.Pass) // test - }) + return c.SendString(out.Pass) // test + }) - app.Listen(":3000") + app.Listen(":3000") } // curl -X GET -H "Content-Type: application/toml" --data "name = 'bar' // pass = 'test'" localhost:3000 ``` + ### Defining 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: + ```go type Query struct { - Name string `query:"name"` + Name string `query:"name"` } type structValidator struct{} func (v *structValidator) Engine() any { - return "" + return "" } func (v *structValidator) ValidateStruct(out any) error { - out = reflect.ValueOf(out).Elem().Interface() - sq := out.(Query) + out = reflect.ValueOf(out).Elem().Interface() + sq := out.(Query) - if sq.Name != "john" { - return errors.New("you should have entered right name!") - } + if sq.Name != "john" { + return errors.New("you should have entered right name!") + } - return nil + 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 c.SendString(out.Name) - }) + 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 c.SendString(out.Name) + }) - app.Listen(":3000") + app.Listen(":3000") } // Run tests with the following curl command: // curl "http://localhost:3000/?name=efe" -``` \ No newline at end of file +``` diff --git a/docs/api/app.md b/docs/api/app.md index 164b1edcba..c3ecb552f8 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -43,19 +43,19 @@ func (app *App) MountPath() string ```go title="Examples" func main() { - app := fiber.New() - one := fiber.New() - two := fiber.New() - three := fiber.New() - - two.Use("/three", three) - one.Use("/two", two) - app.Use("/one", one) + app := fiber.New() + one := fiber.New() + two := fiber.New() + three := fiber.New() + + two.Use("/three", three) + one.Use("/two", two) + app.Use("/one", one) - one.MountPath() // "/one" - two.MountPath() // "/one/two" - three.MountPath() // "/one/two/three" - app.MountPath() // "" + one.MountPath() // "/one" + two.MountPath() // "/one/two" + three.MountPath() // "/one/two/three" + app.MountPath() // "" } ``` @@ -91,7 +91,7 @@ func main() { ### Route -Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. +Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. Similar to [`Express`](https://expressjs.com/de/api.html#app.route). @@ -120,6 +120,7 @@ type Register interface { Route(path string) Register } ``` + ```go title="Examples" @@ -222,6 +223,7 @@ func main() { ] ] ``` + ### Name @@ -328,6 +330,7 @@ func main() { null ] ``` + ### GetRoute @@ -347,10 +350,10 @@ func main() { app.Get("/", handler).Name("index") data, _ := json.MarshalIndent(app.GetRoute("index"), "", " ") - fmt.Print(string(data)) + fmt.Print(string(data)) - app.Listen(":3000") + app.Listen(":3000") } ``` @@ -365,6 +368,7 @@ func main() { "params": null } ``` + ### GetRoutes @@ -376,14 +380,15 @@ func (app *App) GetRoutes(filterUseOption ...bool) []Route ``` When filterUseOption equal to true, it will filter the routes registered by the middleware. + ```go title="Examples" func main() { - app := fiber.New() - app.Post("/", func (c fiber.Ctx) error { - return c.SendString("Hello, World!") - }).Name("index") - data, _ := json.MarshalIndent(app.GetRoutes(true), "", " ") - fmt.Print(string(data)) + app := fiber.New() + app.Post("/", func (c fiber.Ctx) error { + return c.SendString("Hello, World!") + }).Name("index") + data, _ := json.MarshalIndent(app.GetRoutes(true), "", " ") + fmt.Print(string(data)) } ``` @@ -400,6 +405,7 @@ func main() { } ] ``` + ## Config @@ -436,12 +442,12 @@ func (app *App) NewCtxFunc(function func(app *App) CustomCtx) ```go title="Examples" type CustomCtx struct { - DefaultCtx + DefaultCtx } // Custom method func (c *CustomCtx) Params(key string, defaultValue ...string) string { - return "prefix_" + c.DefaultCtx.Params(key) + return "prefix_" + c.DefaultCtx.Params(key) } app := New() @@ -521,7 +527,6 @@ func (app *App) RegisterCustomConstraint(constraint CustomConstraint) See [Custom Constraint](../guide/routing.md#custom-constraint) section for more information. - ## SetTLSHandler Use SetTLSHandler to set [ClientHelloInfo](https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2) when using TLS with Listener. diff --git a/docs/api/bind.md b/docs/api/bind.md index f955202e28..f01c4b870e 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -15,14 +15,13 @@ Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more.. ::: - ## Binders - [Body](#body) - - [Form](#form) - - [JSON](#json) - - [MultipartForm](#multipartform) - - [XML](#xml) + - [Form](#form) + - [JSON](#json) + - [MultipartForm](#multipartform) + - [XML](#xml) - [Cookie](#cookie) - [Header](#header) - [Query](#query) @@ -80,7 +79,6 @@ app.Post("/", func(c fiber.Ctx) error { // curl -X POST "http://localhost:3000/?name=john&pass=doe" ``` - **The methods for the various bodies can also be used directly:** #### Form @@ -89,7 +87,6 @@ Binds the request form body to a struct. It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a Form body with a field called Pass, you would use a struct field of `form:"pass"`. - ```go title="Signature" func (b *Bind) Form(out any) error ``` @@ -125,7 +122,6 @@ Binds the request json body to a struct. It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a JSON body with a field called Pass, you would use a struct field of `json:"pass"`. - ```go title="Signature" func (b *Bind) JSON(out any) error ``` @@ -162,7 +158,6 @@ Binds the request multipart form body to a struct. It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a MultipartForm body with a field called Pass, you would use a struct field of `form:"pass"`. - ```go title="Signature" func (b *Bind) MultipartForm(out any) error ``` @@ -199,7 +194,6 @@ Binds the request xml form body to a struct. It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a XML body with a field called Pass, you would use a struct field of `xml:"pass"`. - ```go title="Signature" func (b *Bind) XML(out any) error ``` @@ -229,7 +223,6 @@ app.Post("/", func(c fiber.Ctx) error { // curl -X POST -H "Content-Type: application/xml" --data "johndoe" localhost:3000 ``` - ### Cookie This method is similar to [Body-Binding](#body), but for cookie parameters. @@ -262,7 +255,6 @@ app.Get("/", func(c fiber.Ctx) error { // curl.exe --cookie "name=Joseph; age=23; job=true" http://localhost:8000/ ``` - ### Header This method is similar to [Body-Binding](#body), but for request headers. @@ -298,7 +290,6 @@ app.Get("/", func(c fiber.Ctx) error { // curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat" ``` - ### Query This method is similar to [Body-Binding](#body), but for query parameters. @@ -342,7 +333,6 @@ app.Get("/", func(c fiber.Ctx) error { For more parser settings please look here [Config](fiber.md#enablesplittingonparsers) ::: - ### RespHeader This method is similar to [Body-Binding](#body), but for response headers. @@ -467,7 +457,6 @@ It's default behavior of binder. func (b *Bind) Should() *Bind ``` - ## SetParserDecoder Allow you to config BodyParser/QueryParser decoder, base on schema's options, providing possibility to add custom type for parsing. @@ -542,7 +531,6 @@ app.Get("/query", func(c fiber.Ctx) error { ``` - ## Validation Validation is also possible with the binding methods. You can specify your validation rules using the `validate` struct tag. @@ -585,6 +573,3 @@ app.Post("/", func(c fiber.Ctx) error { } }) ``` - - - diff --git a/docs/api/constants.md b/docs/api/constants.md index a9ee6d5a05..9fbff533cb 100644 --- a/docs/api/constants.md +++ b/docs/api/constants.md @@ -5,7 +5,7 @@ description: Some constants for Fiber. sidebar_position: 8 --- -### HTTP methods were copied from net/http. +### HTTP methods were copied from net/http ```go const ( @@ -26,94 +26,94 @@ const ( ```go const ( - MIMETextXML = "text/xml" - MIMETextHTML = "text/html" - MIMETextPlain = "text/plain" - MIMETextJavaScript = "text/javascript" - MIMETextCSS = "text/css" - MIMEApplicationXML = "application/xml" + MIMETextXML = "text/xml" + MIMETextHTML = "text/html" + MIMETextPlain = "text/plain" + MIMETextJavaScript = "text/javascript" + MIMETextCSS = "text/css" + MIMEApplicationXML = "application/xml" MIMEApplicationJSON = "application/json" - MIMEApplicationJavaScript = "application/javascript" - MIMEApplicationForm = "application/x-www-form-urlencoded" - MIMEOctetStream = "application/octet-stream" - MIMEMultipartForm = "multipart/form-data" + MIMEApplicationJavaScript = "application/javascript" + MIMEApplicationForm = "application/x-www-form-urlencoded" + MIMEOctetStream = "application/octet-stream" + MIMEMultipartForm = "multipart/form-data" - MIMETextXMLCharsetUTF8 = "text/xml; charset=utf-8" - MIMETextHTMLCharsetUTF8 = "text/html; charset=utf-8" - MIMETextPlainCharsetUTF8 = "text/plain; charset=utf-8" - MIMETextJavaScriptCharsetUTF8 = "text/javascript; charset=utf-8" - MIMETextCSSCharsetUTF8 = "text/css; charset=utf-8" - MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=utf-8" - MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8" - MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8" + MIMETextXMLCharsetUTF8 = "text/xml; charset=utf-8" + MIMETextHTMLCharsetUTF8 = "text/html; charset=utf-8" + MIMETextPlainCharsetUTF8 = "text/plain; charset=utf-8" + MIMETextJavaScriptCharsetUTF8 = "text/javascript; charset=utf-8" + MIMETextCSSCharsetUTF8 = "text/css; charset=utf-8" + MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=utf-8" + MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8" + MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8" )``` ### HTTP status codes were copied from net/http. ```go const ( - StatusContinue = 100 // RFC 7231, 6.2.1 - StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2 - StatusProcessing = 102 // RFC 2518, 10.1 - StatusEarlyHints = 103 // RFC 8297 - StatusOK = 200 // RFC 7231, 6.3.1 - StatusCreated = 201 // RFC 7231, 6.3.2 - StatusAccepted = 202 // RFC 7231, 6.3.3 - StatusNonAuthoritativeInformation = 203 // RFC 7231, 6.3.4 - StatusNoContent = 204 // RFC 7231, 6.3.5 - StatusResetContent = 205 // RFC 7231, 6.3.6 - StatusPartialContent = 206 // RFC 7233, 4.1 - StatusMultiStatus = 207 // RFC 4918, 11.1 - StatusAlreadyReported = 208 // RFC 5842, 7.1 - StatusIMUsed = 226 // RFC 3229, 10.4.1 - StatusMultipleChoices = 300 // RFC 7231, 6.4.1 - StatusMovedPermanently = 301 // RFC 7231, 6.4.2 - StatusFound = 302 // RFC 7231, 6.4.3 - StatusSeeOther = 303 // RFC 7231, 6.4.4 - StatusNotModified = 304 // RFC 7232, 4.1 - StatusUseProxy = 305 // RFC 7231, 6.4.5 - StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7 - StatusPermanentRedirect = 308 // RFC 7538, 3 - StatusBadRequest = 400 // RFC 7231, 6.5.1 - StatusUnauthorized = 401 // RFC 7235, 3.1 - StatusPaymentRequired = 402 // RFC 7231, 6.5.2 - StatusForbidden = 403 // RFC 7231, 6.5.3 - StatusNotFound = 404 // RFC 7231, 6.5.4 - StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5 - StatusNotAcceptable = 406 // RFC 7231, 6.5.6 - StatusProxyAuthRequired = 407 // RFC 7235, 3.2 - StatusRequestTimeout = 408 // RFC 7231, 6.5.7 - StatusConflict = 409 // RFC 7231, 6.5.8 - StatusGone = 410 // RFC 7231, 6.5.9 - StatusLengthRequired = 411 // RFC 7231, 6.5.10 - StatusPreconditionFailed = 412 // RFC 7232, 4.2 - StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11 - StatusRequestURITooLong = 414 // RFC 7231, 6.5.12 - StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13 - StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4 - StatusExpectationFailed = 417 // RFC 7231, 6.5.14 - StatusTeapot = 418 // RFC 7168, 2.3.3 - StatusMisdirectedRequest = 421 // RFC 7540, 9.1.2 - StatusUnprocessableEntity = 422 // RFC 4918, 11.2 - StatusLocked = 423 // RFC 4918, 11.3 - StatusFailedDependency = 424 // RFC 4918, 11.4 - StatusTooEarly = 425 // RFC 8470, 5.2. - StatusUpgradeRequired = 426 // RFC 7231, 6.5.15 - StatusPreconditionRequired = 428 // RFC 6585, 3 - StatusTooManyRequests = 429 // RFC 6585, 4 - StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5 - StatusUnavailableForLegalReasons = 451 // RFC 7725, 3 - StatusInternalServerError = 500 // RFC 7231, 6.6.1 - StatusNotImplemented = 501 // RFC 7231, 6.6.2 - StatusBadGateway = 502 // RFC 7231, 6.6.3 - StatusServiceUnavailable = 503 // RFC 7231, 6.6.4 - StatusGatewayTimeout = 504 // RFC 7231, 6.6.5 - StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6 - StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1 - StatusInsufficientStorage = 507 // RFC 4918, 11.5 - StatusLoopDetected = 508 // RFC 5842, 7.2 - StatusNotExtended = 510 // RFC 2774, 7 - StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6 + StatusContinue = 100 // RFC 7231, 6.2.1 + StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2 + StatusProcessing = 102 // RFC 2518, 10.1 + StatusEarlyHints = 103 // RFC 8297 + StatusOK = 200 // RFC 7231, 6.3.1 + StatusCreated = 201 // RFC 7231, 6.3.2 + StatusAccepted = 202 // RFC 7231, 6.3.3 + StatusNonAuthoritativeInformation = 203 // RFC 7231, 6.3.4 + StatusNoContent = 204 // RFC 7231, 6.3.5 + StatusResetContent = 205 // RFC 7231, 6.3.6 + StatusPartialContent = 206 // RFC 7233, 4.1 + StatusMultiStatus = 207 // RFC 4918, 11.1 + StatusAlreadyReported = 208 // RFC 5842, 7.1 + StatusIMUsed = 226 // RFC 3229, 10.4.1 + StatusMultipleChoices = 300 // RFC 7231, 6.4.1 + StatusMovedPermanently = 301 // RFC 7231, 6.4.2 + StatusFound = 302 // RFC 7231, 6.4.3 + StatusSeeOther = 303 // RFC 7231, 6.4.4 + StatusNotModified = 304 // RFC 7232, 4.1 + StatusUseProxy = 305 // RFC 7231, 6.4.5 + StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7 + StatusPermanentRedirect = 308 // RFC 7538, 3 + StatusBadRequest = 400 // RFC 7231, 6.5.1 + StatusUnauthorized = 401 // RFC 7235, 3.1 + StatusPaymentRequired = 402 // RFC 7231, 6.5.2 + StatusForbidden = 403 // RFC 7231, 6.5.3 + StatusNotFound = 404 // RFC 7231, 6.5.4 + StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5 + StatusNotAcceptable = 406 // RFC 7231, 6.5.6 + StatusProxyAuthRequired = 407 // RFC 7235, 3.2 + StatusRequestTimeout = 408 // RFC 7231, 6.5.7 + StatusConflict = 409 // RFC 7231, 6.5.8 + StatusGone = 410 // RFC 7231, 6.5.9 + StatusLengthRequired = 411 // RFC 7231, 6.5.10 + StatusPreconditionFailed = 412 // RFC 7232, 4.2 + StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11 + StatusRequestURITooLong = 414 // RFC 7231, 6.5.12 + StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13 + StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4 + StatusExpectationFailed = 417 // RFC 7231, 6.5.14 + StatusTeapot = 418 // RFC 7168, 2.3.3 + StatusMisdirectedRequest = 421 // RFC 7540, 9.1.2 + StatusUnprocessableEntity = 422 // RFC 4918, 11.2 + StatusLocked = 423 // RFC 4918, 11.3 + StatusFailedDependency = 424 // RFC 4918, 11.4 + StatusTooEarly = 425 // RFC 8470, 5.2. + StatusUpgradeRequired = 426 // RFC 7231, 6.5.15 + StatusPreconditionRequired = 428 // RFC 6585, 3 + StatusTooManyRequests = 429 // RFC 6585, 4 + StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5 + StatusUnavailableForLegalReasons = 451 // RFC 7725, 3 + StatusInternalServerError = 500 // RFC 7231, 6.6.1 + StatusNotImplemented = 501 // RFC 7231, 6.6.2 + StatusBadGateway = 502 // RFC 7231, 6.6.3 + StatusServiceUnavailable = 503 // RFC 7231, 6.6.4 + StatusGatewayTimeout = 504 // RFC 7231, 6.6.5 + StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6 + StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1 + StatusInsufficientStorage = 507 // RFC 4918, 11.5 + StatusLoopDetected = 508 // RFC 5842, 7.2 + StatusNotExtended = 510 // RFC 2774, 7 + StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6 ) ``` @@ -121,46 +121,46 @@ const ( ```go var ( - ErrBadRequest = NewError(StatusBadRequest) // RFC 7231, 6.5.1 - ErrUnauthorized = NewError(StatusUnauthorized) // RFC 7235, 3.1 - ErrPaymentRequired = NewError(StatusPaymentRequired) // RFC 7231, 6.5.2 - ErrForbidden = NewError(StatusForbidden) // RFC 7231, 6.5.3 - ErrNotFound = NewError(StatusNotFound) // RFC 7231, 6.5.4 - ErrMethodNotAllowed = NewError(StatusMethodNotAllowed) // RFC 7231, 6.5.5 - ErrNotAcceptable = NewError(StatusNotAcceptable) // RFC 7231, 6.5.6 - ErrProxyAuthRequired = NewError(StatusProxyAuthRequired) // RFC 7235, 3.2 - ErrRequestTimeout = NewError(StatusRequestTimeout) // RFC 7231, 6.5.7 - ErrConflict = NewError(StatusConflict) // RFC 7231, 6.5.8 - ErrGone = NewError(StatusGone) // RFC 7231, 6.5.9 - ErrLengthRequired = NewError(StatusLengthRequired) // RFC 7231, 6.5.10 - ErrPreconditionFailed = NewError(StatusPreconditionFailed) // RFC 7232, 4.2 - ErrRequestEntityTooLarge = NewError(StatusRequestEntityTooLarge) // RFC 7231, 6.5.11 - ErrRequestURITooLong = NewError(StatusRequestURITooLong) // RFC 7231, 6.5.12 - ErrUnsupportedMediaType = NewError(StatusUnsupportedMediaType) // RFC 7231, 6.5.13 - ErrRequestedRangeNotSatisfiable = NewError(StatusRequestedRangeNotSatisfiable) // RFC 7233, 4.4 - ErrExpectationFailed = NewError(StatusExpectationFailed) // RFC 7231, 6.5.14 - ErrTeapot = NewError(StatusTeapot) // RFC 7168, 2.3.3 - ErrMisdirectedRequest = NewError(StatusMisdirectedRequest) // RFC 7540, 9.1.2 - ErrUnprocessableEntity = NewError(StatusUnprocessableEntity) // RFC 4918, 11.2 - ErrLocked = NewError(StatusLocked) // RFC 4918, 11.3 - ErrFailedDependency = NewError(StatusFailedDependency) // RFC 4918, 11.4 - ErrTooEarly = NewError(StatusTooEarly) // RFC 8470, 5.2. - ErrUpgradeRequired = NewError(StatusUpgradeRequired) // RFC 7231, 6.5.15 - ErrPreconditionRequired = NewError(StatusPreconditionRequired) // RFC 6585, 3 - ErrTooManyRequests = NewError(StatusTooManyRequests) // RFC 6585, 4 - ErrRequestHeaderFieldsTooLarge = NewError(StatusRequestHeaderFieldsTooLarge) // RFC 6585, 5 - ErrUnavailableForLegalReasons = NewError(StatusUnavailableForLegalReasons) // RFC 7725, 3 - ErrInternalServerError = NewError(StatusInternalServerError) // RFC 7231, 6.6.1 - ErrNotImplemented = NewError(StatusNotImplemented) // RFC 7231, 6.6.2 - ErrBadGateway = NewError(StatusBadGateway) // RFC 7231, 6.6.3 - ErrServiceUnavailable = NewError(StatusServiceUnavailable) // RFC 7231, 6.6.4 - ErrGatewayTimeout = NewError(StatusGatewayTimeout) // RFC 7231, 6.6.5 - ErrHTTPVersionNotSupported = NewError(StatusHTTPVersionNotSupported) // RFC 7231, 6.6.6 - ErrVariantAlsoNegotiates = NewError(StatusVariantAlsoNegotiates) // RFC 2295, 8.1 - ErrInsufficientStorage = NewError(StatusInsufficientStorage) // RFC 4918, 11.5 - ErrLoopDetected = NewError(StatusLoopDetected) // RFC 5842, 7.2 - ErrNotExtended = NewError(StatusNotExtended) // RFC 2774, 7 - ErrNetworkAuthenticationRequired = NewError(StatusNetworkAuthenticationRequired) // RFC 6585, 6 + ErrBadRequest = NewError(StatusBadRequest) // RFC 7231, 6.5.1 + ErrUnauthorized = NewError(StatusUnauthorized) // RFC 7235, 3.1 + ErrPaymentRequired = NewError(StatusPaymentRequired) // RFC 7231, 6.5.2 + ErrForbidden = NewError(StatusForbidden) // RFC 7231, 6.5.3 + ErrNotFound = NewError(StatusNotFound) // RFC 7231, 6.5.4 + ErrMethodNotAllowed = NewError(StatusMethodNotAllowed) // RFC 7231, 6.5.5 + ErrNotAcceptable = NewError(StatusNotAcceptable) // RFC 7231, 6.5.6 + ErrProxyAuthRequired = NewError(StatusProxyAuthRequired) // RFC 7235, 3.2 + ErrRequestTimeout = NewError(StatusRequestTimeout) // RFC 7231, 6.5.7 + ErrConflict = NewError(StatusConflict) // RFC 7231, 6.5.8 + ErrGone = NewError(StatusGone) // RFC 7231, 6.5.9 + ErrLengthRequired = NewError(StatusLengthRequired) // RFC 7231, 6.5.10 + ErrPreconditionFailed = NewError(StatusPreconditionFailed) // RFC 7232, 4.2 + ErrRequestEntityTooLarge = NewError(StatusRequestEntityTooLarge) // RFC 7231, 6.5.11 + ErrRequestURITooLong = NewError(StatusRequestURITooLong) // RFC 7231, 6.5.12 + ErrUnsupportedMediaType = NewError(StatusUnsupportedMediaType) // RFC 7231, 6.5.13 + ErrRequestedRangeNotSatisfiable = NewError(StatusRequestedRangeNotSatisfiable) // RFC 7233, 4.4 + ErrExpectationFailed = NewError(StatusExpectationFailed) // RFC 7231, 6.5.14 + ErrTeapot = NewError(StatusTeapot) // RFC 7168, 2.3.3 + ErrMisdirectedRequest = NewError(StatusMisdirectedRequest) // RFC 7540, 9.1.2 + ErrUnprocessableEntity = NewError(StatusUnprocessableEntity) // RFC 4918, 11.2 + ErrLocked = NewError(StatusLocked) // RFC 4918, 11.3 + ErrFailedDependency = NewError(StatusFailedDependency) // RFC 4918, 11.4 + ErrTooEarly = NewError(StatusTooEarly) // RFC 8470, 5.2. + ErrUpgradeRequired = NewError(StatusUpgradeRequired) // RFC 7231, 6.5.15 + ErrPreconditionRequired = NewError(StatusPreconditionRequired) // RFC 6585, 3 + ErrTooManyRequests = NewError(StatusTooManyRequests) // RFC 6585, 4 + ErrRequestHeaderFieldsTooLarge = NewError(StatusRequestHeaderFieldsTooLarge) // RFC 6585, 5 + ErrUnavailableForLegalReasons = NewError(StatusUnavailableForLegalReasons) // RFC 7725, 3 + ErrInternalServerError = NewError(StatusInternalServerError) // RFC 7231, 6.6.1 + ErrNotImplemented = NewError(StatusNotImplemented) // RFC 7231, 6.6.2 + ErrBadGateway = NewError(StatusBadGateway) // RFC 7231, 6.6.3 + ErrServiceUnavailable = NewError(StatusServiceUnavailable) // RFC 7231, 6.6.4 + ErrGatewayTimeout = NewError(StatusGatewayTimeout) // RFC 7231, 6.6.5 + ErrHTTPVersionNotSupported = NewError(StatusHTTPVersionNotSupported) // RFC 7231, 6.6.6 + ErrVariantAlsoNegotiates = NewError(StatusVariantAlsoNegotiates) // RFC 2295, 8.1 + ErrInsufficientStorage = NewError(StatusInsufficientStorage) // RFC 4918, 11.5 + ErrLoopDetected = NewError(StatusLoopDetected) // RFC 5842, 7.2 + ErrNotExtended = NewError(StatusNotExtended) // RFC 2774, 7 + ErrNetworkAuthenticationRequired = NewError(StatusNetworkAuthenticationRequired) // RFC 6585, 6 ) ``` @@ -168,127 +168,127 @@ HTTP Headers were copied from net/http. ```go const ( - HeaderAuthorization = "Authorization" - HeaderProxyAuthenticate = "Proxy-Authenticate" - HeaderProxyAuthorization = "Proxy-Authorization" - HeaderWWWAuthenticate = "WWW-Authenticate" - HeaderAge = "Age" - HeaderCacheControl = "Cache-Control" - HeaderClearSiteData = "Clear-Site-Data" - HeaderExpires = "Expires" - HeaderPragma = "Pragma" - HeaderWarning = "Warning" - HeaderAcceptCH = "Accept-CH" - HeaderAcceptCHLifetime = "Accept-CH-Lifetime" - HeaderContentDPR = "Content-DPR" - HeaderDPR = "DPR" - HeaderEarlyData = "Early-Data" - HeaderSaveData = "Save-Data" - HeaderViewportWidth = "Viewport-Width" - HeaderWidth = "Width" - HeaderETag = "ETag" - HeaderIfMatch = "If-Match" - HeaderIfModifiedSince = "If-Modified-Since" - HeaderIfNoneMatch = "If-None-Match" - HeaderIfUnmodifiedSince = "If-Unmodified-Since" - HeaderLastModified = "Last-Modified" - HeaderVary = "Vary" - HeaderConnection = "Connection" - HeaderKeepAlive = "Keep-Alive" - HeaderAccept = "Accept" - HeaderAcceptCharset = "Accept-Charset" - HeaderAcceptEncoding = "Accept-Encoding" - HeaderAcceptLanguage = "Accept-Language" - HeaderCookie = "Cookie" - HeaderExpect = "Expect" - HeaderMaxForwards = "Max-Forwards" - HeaderSetCookie = "Set-Cookie" - HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials" - HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers" - HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods" - HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin" - HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers" - HeaderAccessControlMaxAge = "Access-Control-Max-Age" - HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers" - HeaderAccessControlRequestMethod = "Access-Control-Request-Method" - HeaderOrigin = "Origin" - HeaderTimingAllowOrigin = "Timing-Allow-Origin" - HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies" - HeaderDNT = "DNT" - HeaderTk = "Tk" - HeaderContentDisposition = "Content-Disposition" - HeaderContentEncoding = "Content-Encoding" - HeaderContentLanguage = "Content-Language" - HeaderContentLength = "Content-Length" - HeaderContentLocation = "Content-Location" - HeaderContentType = "Content-Type" - HeaderForwarded = "Forwarded" - HeaderVia = "Via" - HeaderXForwardedFor = "X-Forwarded-For" - HeaderXForwardedHost = "X-Forwarded-Host" - HeaderXForwardedProto = "X-Forwarded-Proto" - HeaderXForwardedProtocol = "X-Forwarded-Protocol" - HeaderXForwardedSsl = "X-Forwarded-Ssl" - HeaderXUrlScheme = "X-Url-Scheme" - HeaderLocation = "Location" - HeaderFrom = "From" - HeaderHost = "Host" - HeaderReferer = "Referer" - HeaderReferrerPolicy = "Referrer-Policy" - HeaderUserAgent = "User-Agent" - HeaderAllow = "Allow" - HeaderServer = "Server" - HeaderAcceptRanges = "Accept-Ranges" - HeaderContentRange = "Content-Range" - HeaderIfRange = "If-Range" - HeaderRange = "Range" - HeaderContentSecurityPolicy = "Content-Security-Policy" - HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only" - HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy" - HeaderExpectCT = "Expect-CT" - HeaderFeaturePolicy = "Feature-Policy" - HeaderPublicKeyPins = "Public-Key-Pins" - HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only" - HeaderStrictTransportSecurity = "Strict-Transport-Security" - HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests" - HeaderXContentTypeOptions = "X-Content-Type-Options" - HeaderXDownloadOptions = "X-Download-Options" - HeaderXFrameOptions = "X-Frame-Options" - HeaderXPoweredBy = "X-Powered-By" - HeaderXXSSProtection = "X-XSS-Protection" - HeaderLastEventID = "Last-Event-ID" - HeaderNEL = "NEL" - HeaderPingFrom = "Ping-From" - HeaderPingTo = "Ping-To" - HeaderReportTo = "Report-To" - HeaderTE = "TE" - HeaderTrailer = "Trailer" - HeaderTransferEncoding = "Transfer-Encoding" - HeaderSecWebSocketAccept = "Sec-WebSocket-Accept" - HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions" - HeaderSecWebSocketKey = "Sec-WebSocket-Key" - HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol" - HeaderSecWebSocketVersion = "Sec-WebSocket-Version" - HeaderAcceptPatch = "Accept-Patch" - HeaderAcceptPushPolicy = "Accept-Push-Policy" - HeaderAcceptSignature = "Accept-Signature" - HeaderAltSvc = "Alt-Svc" - HeaderDate = "Date" - HeaderIndex = "Index" - HeaderLargeAllocation = "Large-Allocation" - HeaderLink = "Link" - HeaderPushPolicy = "Push-Policy" - HeaderRetryAfter = "Retry-After" - HeaderServerTiming = "Server-Timing" - HeaderSignature = "Signature" - HeaderSignedHeaders = "Signed-Headers" - HeaderSourceMap = "SourceMap" - HeaderUpgrade = "Upgrade" - HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control" - HeaderXPingback = "X-Pingback" - HeaderXRequestID = "X-Request-ID" - HeaderXRequestedWith = "X-Requested-With" - HeaderXRobotsTag = "X-Robots-Tag" - HeaderXUACompatible = "X-UA-Compatible" + HeaderAuthorization = "Authorization" + HeaderProxyAuthenticate = "Proxy-Authenticate" + HeaderProxyAuthorization = "Proxy-Authorization" + HeaderWWWAuthenticate = "WWW-Authenticate" + HeaderAge = "Age" + HeaderCacheControl = "Cache-Control" + HeaderClearSiteData = "Clear-Site-Data" + HeaderExpires = "Expires" + HeaderPragma = "Pragma" + HeaderWarning = "Warning" + HeaderAcceptCH = "Accept-CH" + HeaderAcceptCHLifetime = "Accept-CH-Lifetime" + HeaderContentDPR = "Content-DPR" + HeaderDPR = "DPR" + HeaderEarlyData = "Early-Data" + HeaderSaveData = "Save-Data" + HeaderViewportWidth = "Viewport-Width" + HeaderWidth = "Width" + HeaderETag = "ETag" + HeaderIfMatch = "If-Match" + HeaderIfModifiedSince = "If-Modified-Since" + HeaderIfNoneMatch = "If-None-Match" + HeaderIfUnmodifiedSince = "If-Unmodified-Since" + HeaderLastModified = "Last-Modified" + HeaderVary = "Vary" + HeaderConnection = "Connection" + HeaderKeepAlive = "Keep-Alive" + HeaderAccept = "Accept" + HeaderAcceptCharset = "Accept-Charset" + HeaderAcceptEncoding = "Accept-Encoding" + HeaderAcceptLanguage = "Accept-Language" + HeaderCookie = "Cookie" + HeaderExpect = "Expect" + HeaderMaxForwards = "Max-Forwards" + HeaderSetCookie = "Set-Cookie" + HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials" + HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers" + HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods" + HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin" + HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers" + HeaderAccessControlMaxAge = "Access-Control-Max-Age" + HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers" + HeaderAccessControlRequestMethod = "Access-Control-Request-Method" + HeaderOrigin = "Origin" + HeaderTimingAllowOrigin = "Timing-Allow-Origin" + HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies" + HeaderDNT = "DNT" + HeaderTk = "Tk" + HeaderContentDisposition = "Content-Disposition" + HeaderContentEncoding = "Content-Encoding" + HeaderContentLanguage = "Content-Language" + HeaderContentLength = "Content-Length" + HeaderContentLocation = "Content-Location" + HeaderContentType = "Content-Type" + HeaderForwarded = "Forwarded" + HeaderVia = "Via" + HeaderXForwardedFor = "X-Forwarded-For" + HeaderXForwardedHost = "X-Forwarded-Host" + HeaderXForwardedProto = "X-Forwarded-Proto" + HeaderXForwardedProtocol = "X-Forwarded-Protocol" + HeaderXForwardedSsl = "X-Forwarded-Ssl" + HeaderXUrlScheme = "X-Url-Scheme" + HeaderLocation = "Location" + HeaderFrom = "From" + HeaderHost = "Host" + HeaderReferer = "Referer" + HeaderReferrerPolicy = "Referrer-Policy" + HeaderUserAgent = "User-Agent" + HeaderAllow = "Allow" + HeaderServer = "Server" + HeaderAcceptRanges = "Accept-Ranges" + HeaderContentRange = "Content-Range" + HeaderIfRange = "If-Range" + HeaderRange = "Range" + HeaderContentSecurityPolicy = "Content-Security-Policy" + HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only" + HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy" + HeaderExpectCT = "Expect-CT" + HeaderFeaturePolicy = "Feature-Policy" + HeaderPublicKeyPins = "Public-Key-Pins" + HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only" + HeaderStrictTransportSecurity = "Strict-Transport-Security" + HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests" + HeaderXContentTypeOptions = "X-Content-Type-Options" + HeaderXDownloadOptions = "X-Download-Options" + HeaderXFrameOptions = "X-Frame-Options" + HeaderXPoweredBy = "X-Powered-By" + HeaderXXSSProtection = "X-XSS-Protection" + HeaderLastEventID = "Last-Event-ID" + HeaderNEL = "NEL" + HeaderPingFrom = "Ping-From" + HeaderPingTo = "Ping-To" + HeaderReportTo = "Report-To" + HeaderTE = "TE" + HeaderTrailer = "Trailer" + HeaderTransferEncoding = "Transfer-Encoding" + HeaderSecWebSocketAccept = "Sec-WebSocket-Accept" + HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions" + HeaderSecWebSocketKey = "Sec-WebSocket-Key" + HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol" + HeaderSecWebSocketVersion = "Sec-WebSocket-Version" + HeaderAcceptPatch = "Accept-Patch" + HeaderAcceptPushPolicy = "Accept-Push-Policy" + HeaderAcceptSignature = "Accept-Signature" + HeaderAltSvc = "Alt-Svc" + HeaderDate = "Date" + HeaderIndex = "Index" + HeaderLargeAllocation = "Large-Allocation" + HeaderLink = "Link" + HeaderPushPolicy = "Push-Policy" + HeaderRetryAfter = "Retry-After" + HeaderServerTiming = "Server-Timing" + HeaderSignature = "Signature" + HeaderSignedHeaders = "Signed-Headers" + HeaderSourceMap = "SourceMap" + HeaderUpgrade = "Upgrade" + HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control" + HeaderXPingback = "X-Pingback" + HeaderXRequestID = "X-Request-ID" + HeaderXRequestedWith = "X-Requested-With" + HeaderXRobotsTag = "X-Robots-Tag" + HeaderXUACompatible = "X-UA-Compatible" ) ``` diff --git a/docs/api/ctx.md b/docs/api/ctx.md index 0434671cd6..2640512a3e 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -165,7 +165,6 @@ Performs content-negotiation on the [Accept](https://developer.mozilla.org/en-US The supported content types are `text/html`, `text/plain`, `application/json`, and `application/xml`. For more flexible content negotiation, use [Format](ctx.md#format). - :::info If the header is **not** specified or there is **no** proper format, **text/plain** is used. ::: @@ -375,17 +374,17 @@ func (c Ctx) Cookie(cookie *Cookie) ```go type Cookie struct { - Name string `json:"name"` // The name of the cookie - Value string `json:"value"` // The value of the cookie - Path string `json:"path"` // Specifies a URL path which is allowed to receive the cookie - Domain string `json:"domain"` // Specifies the domain which is allowed to receive the cookie - MaxAge int `json:"max_age"` // The maximum age (in seconds) of the cookie - Expires time.Time `json:"expires"` // The expiration date of the cookie - Secure bool `json:"secure"` // Indicates that the cookie should only be transmitted over a secure HTTPS connection - HTTPOnly bool `json:"http_only"` // Indicates that the cookie is accessible only through the HTTP protocol - SameSite string `json:"same_site"` // Controls whether or not a cookie is sent with cross-site requests - Partitioned bool `json:"partitioned"` // Indicates if the cookie is stored in a partitioned cookie jar - SessionOnly bool `json:"session_only"` // Indicates if the cookie is a session-only cookie + Name string `json:"name"` // The name of the cookie + Value string `json:"value"` // The value of the cookie + Path string `json:"path"` // Specifies a URL path which is allowed to receive the cookie + Domain string `json:"domain"` // Specifies the domain which is allowed to receive the cookie + MaxAge int `json:"max_age"` // The maximum age (in seconds) of the cookie + Expires time.Time `json:"expires"` // The expiration date of the cookie + Secure bool `json:"secure"` // Indicates that the cookie should only be transmitted over a secure HTTPS connection + HTTPOnly bool `json:"http_only"` // Indicates that the cookie is accessible only through the HTTP protocol + SameSite string `json:"same_site"` // Controls whether or not a cookie is sent with cross-site requests + Partitioned bool `json:"partitioned"` // Indicates if the cookie is stored in a partitioned cookie jar + SessionOnly bool `json:"session_only"` // Indicates if the cookie is a session-only cookie } ``` @@ -1001,7 +1000,7 @@ app.Get("/admin", func(c fiber.Ctx) error { }) ``` -An alternative version of the Locals method that takes advantage of Go's generics feature is also available. This version +An alternative version of the Locals method that takes advantage of Go's generics feature is also available. This version allows for the manipulation and retrieval of local values within a request's context with a more specific data type. ```go title="Signature" @@ -1023,7 +1022,7 @@ app.Get("/test", func(c Ctx) error { }) ```` -Make sure to understand and correctly implement the Locals method in both its standard and generic form for better control +Make sure to understand and correctly implement the Locals method in both its standard and generic form for better control over route-specific data within your application. ## Location @@ -1206,9 +1205,8 @@ Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more.. ::: - -In certain scenarios, it can be useful to have an alternative approach to handle different types of parameters, not -just strings. This can be achieved using a generic Query function known as `Params[V GenericType](c Ctx, key string, defaultValue ...V) V`. +In certain scenarios, it can be useful to have an alternative approach to handle different types of parameters, not +just strings. This can be achieved using a generic Query function known as `Params[V GenericType](c Ctx, key string, defaultValue ...V) V`. This function is capable of parsing a query string and returning a value of a type that is assumed and specified by `V GenericType`. ```go title="Signature" @@ -1227,6 +1225,7 @@ app.Get("/user/:id", func(c fiber.Ctx) error{ ``` The generic Params function supports returning the following data types based on V GenericType: + - Integer: int, int8, int16, int32, int64 - Unsigned integer: uint, uint8, uint16, uint32, uint64 - Floating-point numbers: float32, float64 @@ -1234,7 +1233,6 @@ The generic Params function supports returning the following data types based on - String: string - Byte array: []byte - ## Path Contains the path part of the request URL. Optionally, you could override the path by passing a string. For internal redirects, you might want to call [RestartRouting](ctx.md#restartrouting) instead of [Next](ctx.md#next). @@ -1303,11 +1301,11 @@ func (c Ctx) Queries() map[string]string // GET http://example.com/?name=alex&want_pizza=false&id= app.Get("/", func(c fiber.Ctx) error { - m := c.Queries() - m["name"] // "alex" - m["want_pizza"] // "false" - m["id"] // "" - // ... + m := c.Queries() + m["name"] // "alex" + m["want_pizza"] // "false" + m["id"] // "" + // ... }) ``` @@ -1315,9 +1313,9 @@ app.Get("/", func(c fiber.Ctx) error { // GET http://example.com/?field1=value1&field1=value2&field2=value3 app.Get("/", func (c fiber.Ctx) error { - m := c.Queries() - m["field1"] // "value2" - m["field2"] // value3 + m := c.Queries() + m["field1"] // "value2" + m["field2"] // value3 }) ``` @@ -1325,10 +1323,10 @@ app.Get("/", func (c fiber.Ctx) error { // GET http://example.com/?list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3 app.Get("/", func(c fiber.Ctx) error { - m := c.Queries() - m["list_a"] // "3" - m["list_b[]"] // "3" - m["list_c"] // "1,2,3" + m := c.Queries() + m["list_a"] // "3" + m["list_b[]"] // "3" + m["list_c"] // "1,2,3" }) ``` @@ -1336,9 +1334,9 @@ app.Get("/", func(c fiber.Ctx) error { // GET /api/posts?filters.author.name=John&filters.category.name=Technology app.Get("/", func(c fiber.Ctx) error { - m := c.Queries() - m["filters.author.name"] // John - m["filters.category.name"] // Technology + m := c.Queries() + m["filters.author.name"] // John + m["filters.category.name"] // Technology }) ``` @@ -1346,12 +1344,12 @@ app.Get("/", func(c fiber.Ctx) error { // GET /api/posts?tags=apple,orange,banana&filters[tags]=apple,orange,banana&filters[category][name]=fruits&filters.tags=apple,orange,banana&filters.category.name=fruits app.Get("/", func(c fiber.Ctx) error { - m := c.Queries() - m["tags"] // apple,orange,banana - m["filters[tags]"] // apple,orange,banana - m["filters[category][name]"] // fruits - m["filters.tags"] // apple,orange,banana - m["filters.category.name"] // fruits + m := c.Queries() + m["tags"] // apple,orange,banana + m["filters[tags]"] // apple,orange,banana + m["filters[category][name]"] // fruits + m["filters.tags"] // apple,orange,banana + m["filters.category.name"] // fruits }) ``` @@ -1386,8 +1384,8 @@ Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more.. ::: -In certain scenarios, it can be useful to have an alternative approach to handle different types of query parameters, not -just strings. This can be achieved using a generic Query function known as `Query[V GenericType](c Ctx, key string, defaultValue ...V) V`. +In certain scenarios, it can be useful to have an alternative approach to handle different types of query parameters, not +just strings. This can be achieved using a generic Query function known as `Query[V GenericType](c Ctx, key string, defaultValue ...V) V`. This function is capable of parsing a query string and returning a value of a type that is assumed and specified by `V GenericType`. Here is the signature for the generic Query function: @@ -1410,12 +1408,13 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -In this case, `Query[V GenericType](c Ctx, key string, defaultValue ...V) V` can retrieve 'page' as an integer, 'brand' -as a string, and 'new' as a boolean. The function uses the appropriate parsing function for each specified type to ensure -the correct type is returned. This simplifies the retrieval process of different types of query parameters, making your +In this case, `Query[V GenericType](c Ctx, key string, defaultValue ...V) V` can retrieve 'page' as an integer, 'brand' +as a string, and 'new' as a boolean. The function uses the appropriate parsing function for each specified type to ensure +the correct type is returned. This simplifies the retrieval process of different types of query parameters, making your controller actions cleaner. The generic Query function supports returning the following data types based on V GenericType: + - Integer: int, int8, int16, int32, int64 - Unsigned integer: uint, uint8, uint16, uint32, uint64 - Floating-point numbers: float32, float64 @@ -1464,7 +1463,6 @@ app.Get("/teapot", func(c fiber.Ctx) error { }) ``` - ## Render Renders a view with data and sends a `text/html` response. By default `Render` uses the default [**Go Template engine**](https://pkg.go.dev/html/template/). If you want to use another View engine, please take a look at our [**Template middleware**](https://docs.gofiber.io/template). @@ -1746,7 +1744,7 @@ type SendFile struct { // The value for the Cache-Control HTTP-header // that is set on the file response. MaxAge is defined in seconds. // - // Optional. Default value 0. + // Optional. Default value 0. MaxAge int `json:"max_age"` } ``` diff --git a/docs/api/fiber.md b/docs/api/fiber.md index 08d8b6ae82..8e243ecd76 100644 --- a/docs/api/fiber.md +++ b/docs/api/fiber.md @@ -82,7 +82,6 @@ app := fiber.New(fiber.Config{ | WriteTimeout | `time.Duration` | The maximum duration before timing out writes of the response. The default timeout is unlimited. | `nil` | | XMLEncoder | `utils.XMLMarshal` | Allowing for flexibility in using another XML library for encoding. | `xml.Marshal` | - ## Server listening ### Config @@ -115,7 +114,6 @@ app.Listen(":8080", fiber.ListenConfig{ | OnShutdownSuccess | `func()` | Allows to customize success behavior when gracefully shutting down the server by given signal. | `nil` | | TLSConfigFunc | `func(tlsConfig *tls.Config)` | Allows customizing `tls.Config` as you want. | `nil` | - ### Listen Listen serves HTTP requests from the given address. @@ -215,7 +213,6 @@ func (app *App) ShutdownWithTimeout(timeout time.Duration) error func (app *App) ShutdownWithContext(ctx context.Context) error ``` - ## Helper functions ### NewError diff --git a/docs/api/hooks.md b/docs/api/hooks.md index 8717ba5851..e9102a35d1 100644 --- a/docs/api/hooks.md +++ b/docs/api/hooks.md @@ -8,6 +8,7 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; With Fiber v2.30.0, you can execute custom user functions when to run some methods. Here is a list of this hooks: + - [OnRoute](#onroute) - [OnName](#onname) - [OnGroup](#ongroup) @@ -18,6 +19,7 @@ With Fiber v2.30.0, you can execute custom user functions when to run some metho - [OnMount](#onmount) ## Constants + ```go // Handlers define a function to create hooks for Fiber. type OnRouteHandler = func(Route) error @@ -57,45 +59,46 @@ func (h *Hooks) OnName(handler ...OnNameHandler) package main import ( - "fmt" + "fmt" - "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3" ) func main() { - app := fiber.New() + app := fiber.New() - app.Get("/", func(c fiber.Ctx) error { - return c.SendString(c.Route().Name) - }).Name("index") + app.Get("/", func(c fiber.Ctx) error { + return c.SendString(c.Route().Name) + }).Name("index") - app.Hooks().OnName(func(r fiber.Route) error { - fmt.Print("Name: " + r.Name + ", ") + app.Hooks().OnName(func(r fiber.Route) error { + fmt.Print("Name: " + r.Name + ", ") - return nil - }) + return nil + }) - app.Hooks().OnName(func(r fiber.Route) error { - fmt.Print("Method: " + r.Method + "\n") + app.Hooks().OnName(func(r fiber.Route) error { + fmt.Print("Method: " + r.Method + "\n") - return nil - }) + return nil + }) - app.Get("/add/user", func(c fiber.Ctx) error { - return c.SendString(c.Route().Name) - }).Name("addUser") + app.Get("/add/user", func(c fiber.Ctx) error { + return c.SendString(c.Route().Name) + }).Name("addUser") - app.Delete("/destroy/user", func(c fiber.Ctx) error { - return c.SendString(c.Route().Name) - }).Name("destroyUser") + app.Delete("/destroy/user", func(c fiber.Ctx) error { + return c.SendString(c.Route().Name) + }).Name("destroyUser") - app.Listen(":5000") + app.Listen(":5000") } // Results: // Name: addUser, Method: GET // Name: destroyUser, Method: DELETE ``` + @@ -137,7 +140,7 @@ app := fiber.New(fiber.Config{ app.Hooks().OnListen(func(listenData fiber.ListenData) error { if fiber.IsChild() { - return nil + return nil } scheme := "http" if data.TLS { @@ -184,26 +187,26 @@ func (h *Hooks) OnMount(handler ...OnMountHandler) package main import ( - "fmt" + "fmt" - "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3" ) func main() { - app := New() - app.Get("/", testSimpleHandler).Name("x") + app := New() + app.Get("/", testSimpleHandler).Name("x") - subApp := New() - subApp.Get("/test", testSimpleHandler) + subApp := New() + subApp.Get("/test", testSimpleHandler) - subApp.Hooks().OnMount(func(parent *fiber.App) error { - fmt.Print("Mount path of parent app: "+parent.MountPath()) - // ... + subApp.Hooks().OnMount(func(parent *fiber.App) error { + fmt.Print("Mount path of parent app: "+parent.MountPath()) + // ... - return nil - }) + return nil + }) - app.Mount("/sub", subApp) + app.Mount("/sub", subApp) } // Result: @@ -213,6 +216,5 @@ func main() { - :::caution OnName/OnRoute/OnGroup/OnGroupName hooks are mount-sensitive. If you use one of these routes on sub app and you mount it; paths of routes and groups will start with mount prefix. diff --git a/docs/api/log.md b/docs/api/log.md index 9289967d66..508be9a640 100644 --- a/docs/api/log.md +++ b/docs/api/log.md @@ -13,13 +13,13 @@ Fiber offers a default mechanism for logging to standard output. Additionally, i ```go const ( - LevelTrace Level = iota - LevelDebug - LevelInfo - LevelWarn - LevelError - LevelFatal - LevelPanic + LevelTrace Level = iota + LevelDebug + LevelInfo + LevelWarn + LevelError + LevelFatal + LevelPanic ) ``` @@ -42,9 +42,11 @@ type AllLogger interface { ``` ## Print log + Note: The Fatal level method will terminate the program after printing the log message. Please use it with caution. ### Basic Logging + Logs of different levels can be directly printed. These will be entered into `messageKey`, with the default key being `msg`. ```go @@ -58,6 +60,7 @@ log.Panic("The system is down.") ``` ### Formatted Logging + Logs of different levels can be formatted before printing. All such methods end with an `f`. ```go @@ -69,6 +72,7 @@ log.Fatalf("So Long, and Thanks for All the %s.", "banana") ``` ### Key-Value Logging + Print a message with key-value pairs. If the key and value are not paired correctly, the log will output `KEYVALS UNPAIRED`. ```go @@ -80,6 +84,7 @@ log.Fatalw("", "fruit", "banana") ``` ## Global log + For projects that require a simple, global logging function to print messages at any time, Fiber provides a global log. ```go @@ -113,6 +118,7 @@ fiberlog.SetLogger(customLogger) ``` ## Set Level + `log.SetLevel` sets the minimum level of logs that will be output. The default log level is `LevelTrace`. Note that this method is not **concurrent-safe**. diff --git a/docs/api/redirect.md b/docs/api/redirect.md index e1403b73af..79faa36d45 100644 --- a/docs/api/redirect.md +++ b/docs/api/redirect.md @@ -190,7 +190,6 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` - #### OldInputs Get old input data. Check [WithInput](#withinput) for more information. diff --git a/docs/client/examples.md b/docs/client/examples.md index 2ea79609da..86e73b6512 100644 --- a/docs/client/examples.md +++ b/docs/client/examples.md @@ -18,28 +18,29 @@ import TabItem from '@theme/TabItem'; package main import ( - "encoding/base64" - "fmt" + "encoding/base64" + "fmt" - "github.com/gofiber/fiber/v3/client" + "github.com/gofiber/fiber/v3/client" ) func main() { - cc := client.New() - - out := base64.StdEncoding.EncodeToString([]byte("john:doe")) - resp, err := cc.Get("http://localhost:3000", client.Config{ - Header: map[string]string{ - "Authorization": "Basic " + out, - }, - }) - if err != nil { - panic(err) - } - - fmt.Print(string(resp.Body())) + cc := client.New() + + out := base64.StdEncoding.EncodeToString([]byte("john:doe")) + resp, err := cc.Get("http://localhost:3000", client.Config{ + Header: map[string]string{ + "Authorization": "Basic " + out, + }, + }) + if err != nil { + panic(err) + } + + fmt.Print(string(resp.Body())) } ``` + @@ -47,27 +48,28 @@ func main() { package main import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/basicauth" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/basicauth" ) func main() { - app := fiber.New() - app.Use( - basicauth.New(basicauth.Config{ - Users: map[string]string{ - "john": "doe", - }, - }), - ) - - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") - }) - - app.Listen(":3000") + app := fiber.New() + app.Use( + basicauth.New(basicauth.Config{ + Users: map[string]string{ + "john": "doe", + }, + }), + ) + + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Hello, World!") + }) + + app.Listen(":3000") } ``` + @@ -80,40 +82,41 @@ func main() { package main import ( - "crypto/tls" - "crypto/x509" - "fmt" - "os" + "crypto/tls" + "crypto/x509" + "fmt" + "os" - "github.com/gofiber/fiber/v3/client" + "github.com/gofiber/fiber/v3/client" ) func main() { - cc := client.New() + cc := client.New() - certPool, err := x509.SystemCertPool() - if err != nil { - panic(err) - } + certPool, err := x509.SystemCertPool() + if err != nil { + panic(err) + } - cert, err := os.ReadFile("ssl.cert") - if err != nil { - panic(err) - } + cert, err := os.ReadFile("ssl.cert") + if err != nil { + panic(err) + } - certPool.AppendCertsFromPEM(cert) - cc.SetTLSConfig(&tls.Config{ - RootCAs: certPool, - }) + certPool.AppendCertsFromPEM(cert) + cc.SetTLSConfig(&tls.Config{ + RootCAs: certPool, + }) - resp, err := cc.Get("https://localhost:3000") - if err != nil { - panic(err) - } + resp, err := cc.Get("https://localhost:3000") + if err != nil { + panic(err) + } - fmt.Print(string(resp.Body())) + fmt.Print(string(resp.Body())) } ``` + @@ -121,25 +124,26 @@ func main() { package main import ( - "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3" ) func main() { - app := fiber.New() - - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") - }) - - err := app.Listen(":3000", fiber.ListenConfig{ - CertFile: "ssl.cert", - CertKeyFile: "ssl.key", - }) - if err != nil { - panic(err) - } + app := fiber.New() + + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Hello, World!") + }) + + err := app.Listen(":3000", fiber.ListenConfig{ + CertFile: "ssl.cert", + CertKeyFile: "ssl.key", + }) + if err != nil { + panic(err) + } } ``` + @@ -149,20 +153,20 @@ func main() { ```go func main() { - jar := client.AcquireCookieJar() - defer client.ReleaseCookieJar(jar) + jar := client.AcquireCookieJar() + defer client.ReleaseCookieJar(jar) - cc := client.New() - cc.SetCookieJar(jar) + cc := client.New() + cc.SetCookieJar(jar) - jar.SetKeyValueBytes("httpbin.org", []byte("john"), []byte("doe")) + jar.SetKeyValueBytes("httpbin.org", []byte("john"), []byte("doe")) - resp, err := cc.Get("https://httpbin.org/cookies") - if err != nil { - panic(err) - } + resp, err := cc.Get("https://httpbin.org/cookies") + if err != nil { + panic(err) + } - fmt.Println(string(resp.Body())) + fmt.Println(string(resp.Body())) } ``` @@ -183,23 +187,23 @@ func main() { ```go func main() { - jar := client.AcquireCookieJar() - defer client.ReleaseCookieJar(jar) + jar := client.AcquireCookieJar() + defer client.ReleaseCookieJar(jar) - cc := client.New() - cc.SetCookieJar(jar) + cc := client.New() + cc.SetCookieJar(jar) - _, err := cc.Get("https://httpbin.org/cookies/set/john/doe") - if err != nil { - panic(err) - } + _, err := cc.Get("https://httpbin.org/cookies/set/john/doe") + if err != nil { + panic(err) + } - uri := fasthttp.AcquireURI() - defer fasthttp.ReleaseURI(uri) + uri := fasthttp.AcquireURI() + defer fasthttp.ReleaseURI(uri) - uri.SetHost("httpbin.org") - uri.SetPath("/cookies") - fmt.Println(jar.Get(uri)) + uri.SetHost("httpbin.org") + uri.SetPath("/cookies") + fmt.Println(jar.Get(uri)) } ``` @@ -216,23 +220,23 @@ func main() { ```go func main() { - jar := client.AcquireCookieJar() - defer client.ReleaseCookieJar(jar) + jar := client.AcquireCookieJar() + defer client.ReleaseCookieJar(jar) - cc := client.New() - cc.SetCookieJar(jar) + cc := client.New() + cc.SetCookieJar(jar) - _, err := cc.Get("https://httpbin.org/cookies/set/john/doe") - if err != nil { - panic(err) - } + _, err := cc.Get("https://httpbin.org/cookies/set/john/doe") + if err != nil { + panic(err) + } - resp, err := cc.Get("https://httpbin.org/cookies") - if err != nil { - panic(err) - } + resp, err := cc.Get("https://httpbin.org/cookies") + if err != nil { + panic(err) + } - fmt.Println(resp.String()) + fmt.Println(resp.String()) } ``` diff --git a/docs/client/hooks.md b/docs/client/hooks.md index 3ae510f354..8616eac792 100644 --- a/docs/client/hooks.md +++ b/docs/client/hooks.md @@ -18,43 +18,43 @@ You need to use `RequestHook func(*Client, *Request) error` function signature w ```go 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"` + 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 := client.New() - cc.AddRequestHook(func(c *client.Client, r *client.Request) error { - r.SetURL("https://api.github.com/" + r.URL()) + cc.AddRequestHook(func(c *client.Client, r *client.Request) error { + r.SetURL("https://api.github.com/" + r.URL()) - return nil - }) + return nil + }) - resp, err := cc.Get("repos/gofiber/fiber") - if err != nil { - panic(err) - } + resp, err := cc.Get("repos/gofiber/fiber") + if err != nil { + panic(err) + } - var repo Repository - if err := resp.JSON(&repo); 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("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) + 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) } ``` @@ -87,22 +87,22 @@ If any error returns from request hook execution, it will interrupt the request ```go 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) - } + 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) + } } ``` @@ -129,24 +129,24 @@ You need to use `ResponseHook func(*Client, *Response, *Request) error` function ```go func main() { - cc := client.New() + 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()) + 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) - }) + fmt.Println("Response Headers:") + resp.RawResponse.Header.VisitAll(func(key, value []byte) { + fmt.Printf("%s: %s\n", key, value) + }) - return nil - }) + return nil + }) - _, err := cc.Get("https://example.com/") - if err != nil { - panic(err) - } + _, err := cc.Get("https://example.com/") + if err != nil { + panic(err) + } } ``` @@ -185,27 +185,27 @@ If any error is returned from executing the response hook, it will return the er ```go 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) - } + 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) + } } ``` @@ -231,22 +231,22 @@ Hooks work as FIFO (first-in-first-out). You need to check the order while addin ```go 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) - } + 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) + } } ``` diff --git a/docs/client/request.md b/docs/client/request.md index a5a025bdad..d1126dae0e 100644 --- a/docs/client/request.md +++ b/docs/client/request.md @@ -18,32 +18,31 @@ This structure is designed to be flexible and efficient, allowing users to easil ```go type Request struct { - url string - method string - userAgent string - boundary string - referer string - ctx context.Context - header *Header - params *QueryParam - cookies *Cookie - path *PathParam - - timeout time.Duration - maxRedirects int - - client *Client - - body any - formData *FormData - files []*File - bodyType bodyType - - RawRequest *fasthttp.Request + url string + method string + userAgent string + boundary string + referer string + ctx context.Context + header *Header + params *QueryParam + cookies *Cookie + path *PathParam + + timeout time.Duration + maxRedirects int + + client *Client + + body any + formData *FormData + files []*File + bodyType bodyType + + RawRequest *fasthttp.Request } ``` - ## REST Methods ### Get @@ -207,6 +206,7 @@ func (r *Request) SetContext(ctx context.Context) *Request ## Header Header method returns header value via key, this method will visit all field in the header. + ```go title="Signature" func (r *Request) Header(key string) []string ``` @@ -229,7 +229,7 @@ req.AddHeader("Test", "654321") resp, err := req.Get("https://httpbin.org/headers") if err != nil { - panic(err) + panic(err) } fmt.Println(resp.String()) @@ -271,7 +271,7 @@ req.SetHeader("Test", "654321") resp, err := req.Get("https://httpbin.org/headers") if err != nil { - panic(err) + panic(err) } fmt.Println(resp.String()) @@ -338,7 +338,7 @@ req.AddParam("hobbies", "basketball") resp, err := req.Get("https://httpbin.org/response-headers") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -401,19 +401,19 @@ req := client.AcquireRequest() defer client.ReleaseRequest(req) req.SetParamsWithStruct(struct { - Name string `json:"name"` - Hobbies []string `json:"hobbies"` + Name string `json:"name"` + Hobbies []string `json:"hobbies"` }{ - Name: "John Doe", - Hobbies: []string{ - "Football", - "Basketball", - }, + Name: "John Doe", + Hobbies: []string{ + "Football", + "Basketball", + }, }) resp, err := req.Get("https://httpbin.org/response-headers") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -525,13 +525,13 @@ req := client.AcquireRequest() defer client.ReleaseRequest(req) req.SetCookies(map[string]string{ - "cookie1": "value1", - "cookie2": "value2", + "cookie1": "value1", + "cookie2": "value2", }) resp, err := req.Get("https://httpbin.org/cookies") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -592,7 +592,7 @@ req.SetPathParam("base64", "R29maWJlcg==") resp, err := req.Get("https://httpbin.org/base64/:base64") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -691,7 +691,7 @@ req.AddFormData("points", "100") resp, err := req.Post("https://httpbin.org/post") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -735,7 +735,7 @@ req.SetFormData("email", "john@doe.com") resp, err := req.Post("https://httpbin.org/post") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -832,7 +832,7 @@ req.AddFile("test.txt") resp, err := req.Post("https://httpbin.org/post") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -872,7 +872,7 @@ req.AddFileWithReader("test.txt", io.NopCloser(buf)) resp, err := req.Post("https://httpbin.org/post") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -928,7 +928,7 @@ req.SetTimeout(5 * time.Second) resp, err := req.Get("https://httpbin.org/delay/4") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -957,7 +957,7 @@ req.SetTimeout(5 * time.Second) resp, err := req.Get("https://httpbin.org/delay/6") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -1016,7 +1016,7 @@ Header is a wrapper which wrap http.Header, the header in client and request wil ```go type Header struct { - *fasthttp.RequestHeader + *fasthttp.RequestHeader } ``` @@ -1050,7 +1050,7 @@ QueryParam is a wrapper which wrap url.Values, the query string and formdata in ```go type QueryParam struct { - *fasthttp.Args + *fasthttp.Args } ``` @@ -1229,7 +1229,7 @@ FormData is a wrapper of fasthttp.Args and it is used for url encode body and fi ```go type FormData struct { - *fasthttp.Args + *fasthttp.Args } ``` @@ -1295,10 +1295,10 @@ File is a struct which support send files via request. ```go type File struct { - name string - fieldName string - path string - reader io.ReadCloser + name string + fieldName string + path string + reader io.ReadCloser } ``` diff --git a/docs/client/response.md b/docs/client/response.md index 85ea79c483..2256d400e3 100644 --- a/docs/client/response.md +++ b/docs/client/response.md @@ -17,11 +17,11 @@ This structure allows users to easily access and manage the data returned by the ```go type Response struct { - client *Client - request *Request - cookie []*fasthttp.Cookie + client *Client + request *Request + cookie []*fasthttp.Cookie - RawResponse *fasthttp.Response + RawResponse *fasthttp.Response } ``` @@ -71,7 +71,7 @@ func (r *Response) Protocol() string ```go title="Example" resp, err := client.Get("https://httpbin.org/get") if err != nil { - panic(err) + panic(err) } fmt.Println(resp.Protocol()) @@ -80,7 +80,7 @@ fmt.Println(resp.Protocol())
Click here to see the result -``` +```text HTTP/1.1 ``` @@ -105,19 +105,19 @@ func (r *Response) Cookies() []*fasthttp.Cookie ```go title="Example" resp, err := client.Get("https://httpbin.org/cookies/set/go/fiber") if err != nil { - panic(err) + panic(err) } cookies := resp.Cookies() for _, cookie := range cookies { - fmt.Printf("%s => %s\n", string(cookie.Key()), string(cookie.Value())) + fmt.Printf("%s => %s\n", string(cookie.Key()), string(cookie.Value())) } ```
Click here to see the result -``` +```text go => fiber ``` @@ -149,22 +149,22 @@ func (r *Response) JSON(v any) error ```go title="Example" type Body struct { - Slideshow struct { - Author string `json:"author"` - Date string `json:"date"` - Title string `json:"title"` - } `json:"slideshow"` + Slideshow struct { + Author string `json:"author"` + Date string `json:"date"` + Title string `json:"title"` + } `json:"slideshow"` } var out Body resp, err := client.Get("https://httpbin.org/json") if err != nil { - panic(err) + panic(err) } err = resp.JSON(&out) if err != nil { - panic(err) + panic(err) } fmt.Printf("%+v\n", out) @@ -173,7 +173,7 @@ fmt.Printf("%+v\n", out)
Click here to see the result -``` +```text {Slideshow:{Author:Yours Truly Date:date of publication Title:Sample Slide Show}} ``` diff --git a/docs/client/rest.md b/docs/client/rest.md index 9b34b80f42..3590407e68 100644 --- a/docs/client/rest.md +++ b/docs/client/rest.md @@ -10,36 +10,38 @@ toc_max_heading_level: 5 The Fiber Client for Fiber v3 is a powerful HTTP client optimized for high performance and ease of use in server-side applications. Built on top of the robust FastHTTP library, it inherits FastHTTP's high-speed HTTP protocol implementation. The client is designed to make HTTP requests both internally within services or externally to other web services. ## Features + - **Lightweight & Fast**: Leveraging the minimalistic design of FastHTTP, the Fiber Client is lightweight and extremely fast. - **Flexible Configuration**: Configure client-level settings such as timeouts, headers, and more, which apply to all requests. Specific requests can further override or merge these settings. - **Connection Pooling**: Manages a pool of persistent connections that reduce the overhead of repeatedly establishing connections. - **Timeouts & Retries**: Supports setting request timeouts and retry mechanisms to handle transient failures. ## Usage + To use the Fiber Client, instantiate it with the desired configuration. Here's a simple example: ```go package main import ( - "fmt" - "time" + "fmt" + "time" - "github.com/gofiber/fiber/v3/client" + "github.com/gofiber/fiber/v3/client" ) func main() { - cc := client.New() - cc.SetTimeout(10 * time.Second) + cc := client.New() + cc.SetTimeout(10 * time.Second) - // Get request - resp, err := cc.Get("https://httpbin.org/get") - if err != nil { - panic(err) - } + // Get request + resp, err := cc.Get("https://httpbin.org/get") + if err != nil { + panic(err) + } - fmt.Printf("Status: %d\n", resp.StatusCode()) - fmt.Printf("Body: %s\n", string(resp.Body())) + fmt.Printf("Status: %d\n", resp.StatusCode()) + fmt.Printf("Body: %s\n", string(resp.Body())) } ``` @@ -47,49 +49,49 @@ You can check out [examples](examples.md) for more examples! ```go type Client struct { - mu sync.RWMutex + mu sync.RWMutex - fasthttp *fasthttp.Client + fasthttp *fasthttp.Client - baseURL string - userAgent string - referer string - header *Header - params *QueryParam - cookies *Cookie - path *PathParam + baseURL string + userAgent string + referer string + header *Header + params *QueryParam + cookies *Cookie + path *PathParam - debug bool + debug bool - timeout time.Duration + timeout time.Duration - // user defined request hooks - userRequestHooks []RequestHook + // user defined request hooks + userRequestHooks []RequestHook - // client package defined request hooks - builtinRequestHooks []RequestHook + // client package defined request hooks + builtinRequestHooks []RequestHook - // user defined response hooks - userResponseHooks []ResponseHook + // user defined response hooks + userResponseHooks []ResponseHook - // client package defined response hooks - builtinResponseHooks []ResponseHook + // client package defined response hooks + builtinResponseHooks []ResponseHook - jsonMarshal utils.JSONMarshal - jsonUnmarshal utils.JSONUnmarshal - xmlMarshal utils.XMLMarshal - xmlUnmarshal utils.XMLUnmarshal + jsonMarshal utils.JSONMarshal + jsonUnmarshal utils.JSONUnmarshal + xmlMarshal utils.XMLMarshal + xmlUnmarshal utils.XMLUnmarshal - cookieJar *CookieJar + cookieJar *CookieJar - // proxy - proxyURL string + // proxy + proxyURL string - // retry - retryConfig *RetryConfig + // retry + retryConfig *RetryConfig - // logger - logger log.CommonLogger + // logger + logger log.CommonLogger } ``` @@ -175,21 +177,21 @@ It can be used to configure request data while sending requests using Get, Post, ```go type Config struct { - Ctx context.Context + Ctx context.Context - UserAgent string - Referer string - Header map[string]string - Param map[string]string - Cookie map[string]string - PathParam map[string]string + UserAgent string + Referer string + Header map[string]string + Param map[string]string + Cookie map[string]string + PathParam map[string]string - Timeout time.Duration - MaxRedirects int + Timeout time.Duration + MaxRedirects int - Body any - FormData map[string]string - File []*File + Body any + FormData map[string]string + File []*File } ``` @@ -393,7 +395,7 @@ cc.SetBaseURL("https://httpbin.org/") resp, err := cc.Get("/get") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -402,12 +404,13 @@ fmt.Println(string(resp.Body()))
Click here to see the result -``` +```json { "args": {}, ... } ``` +
### Header @@ -441,7 +444,7 @@ func (c *Client) SetHeader(key, val string) *Client #### AddHeaders AddHeaders method adds multiple headers field and its values at one go in the client instance. -These headers will be applied to all requests raised from this client instance. +These headers will be applied to all requests raised from this client instance. Also it can be overridden at request level headers options. ```go title="Signature" @@ -451,7 +454,7 @@ func (c *Client) AddHeaders(h map[string][]string) *Client #### SetHeaders SetHeaders method sets multiple headers field and its values at one go in the client instance. -These headers will be applied to all requests raised from this client instance. +These headers will be applied to all requests raised from this client instance. Also it can be overridden at request level headers options. ```go title="Signature" @@ -489,7 +492,7 @@ func (c *Client) SetParam(key, val string) *Client #### AddParams AddParams method adds multiple query params field and its values at one go in the client instance. -These params will be applied to all requests raised from this client instance. +These params will be applied to all requests raised from this client instance. Also it can be overridden at request level params options. ```go title="Signature" @@ -499,7 +502,7 @@ func (c *Client) AddParams(m map[string][]string) *Client #### SetParams SetParams method sets multiple params field and its values at one go in the client instance. -These params will be applied to all requests raised from this client instance. +These params will be applied to all requests raised from this client instance. Also it can be overridden at request level params options. ```go title="Signature" @@ -509,7 +512,7 @@ func (c *Client) SetParams(m map[string]string) *Client #### SetParamsWithStruct SetParamsWithStruct method sets multiple params field and its values at one go in the client instance. -These params will be applied to all requests raised from this client instance. +These params will be applied to all requests raised from this client instance. Also it can be overridden at request level params options. ```go title="Signature" @@ -566,7 +569,7 @@ func (c *Client) SetPathParam(key, val string) *Client #### SetPathParams SetPathParams method sets multiple path params field and its values at one go in the client instance. -These path params will be applied to all requests raised from this client instance. +These path params will be applied to all requests raised from this client instance. Also it can be overridden at request level path params options. ```go title="Signature" @@ -576,7 +579,7 @@ func (c *Client) SetPathParams(m map[string]string) *Client #### SetPathParamsWithStruct SetPathParamsWithStruct method sets multiple path params field and its values at one go in the client instance. -These path params will be applied to all requests raised from this client instance. +These path params will be applied to all requests raised from this client instance. Also it can be overridden at request level path params options. ```go title="Signature" @@ -616,7 +619,7 @@ cc.SetCookie("john", "doe") resp, err := cc.Get("https://httpbin.org/cookies") if err != nil { - panic(err) + panic(err) } fmt.Println(string(resp.Body())) @@ -625,19 +628,20 @@ fmt.Println(string(resp.Body()))
Click here to see the result -``` +```json { "cookies": { "john": "doe" } } ``` +
#### SetCookies SetCookies method sets multiple cookies field and its values at one go in the client instance. -These cookies will be applied to all requests raised from this client instance. +These cookies will be applied to all requests raised from this client instance. Also it can be overridden at request level cookie options. ```go title="Signature" diff --git a/docs/extra/faq.md b/docs/extra/faq.md index eaea2a2c41..6731e841ee 100644 --- a/docs/extra/faq.md +++ b/docs/extra/faq.md @@ -20,7 +20,7 @@ Routes and other application-specific logic can live in as many files as you wis ## How do I handle custom 404 responses? -If you're using v2.32.0 or later, all you need to do is to implement a custom error handler. See below, or see a more detailed explanation at [Error Handling](../guide/error-handling.md#custom-error-handler). +If you're using v2.32.0 or later, all you need to do is to implement a custom error handler. See below, or see a more detailed explanation at [Error Handling](../guide/error-handling.md#custom-error-handler). If you're using v2.31.0 or earlier, the error handler will not capture 404 errors. Instead, you need to add a middleware function at the very bottom of the stack \(below all other functions\) to handle a 404 response: @@ -36,8 +36,9 @@ app.Use(func(c fiber.Ctx) error { To use Air in a Fiber project, follow these steps: -1. Install Air by downloading the appropriate binary for your operating system from the GitHub release page or by building the tool directly from source. -2. Create a configuration file for Air in your project directory. This file can be named, for example, .air.toml or air.conf. Here's a sample configuration file that works with Fiber: +* Install Air by downloading the appropriate binary for your operating system from the GitHub release page or by building the tool directly from source. +* Create a configuration file for Air in your project directory. This file can be named, for example, .air.toml or air.conf. Here's a sample configuration file that works with Fiber: + ```toml # .air.toml root = "." @@ -50,7 +51,9 @@ tmp_dir = "tmp" include_ext = ["go", "tpl", "tmpl", "html"] exclude_regex = ["_test\\.go"] ``` -3. Start your Fiber application using Air by running the following command in the terminal: + +* Start your Fiber application using Air by running the following command in the terminal: + ```sh air ``` @@ -59,7 +62,6 @@ As you make changes to your source code, Air will detect them and automatically A complete example demonstrating the use of Air with Fiber can be found in the [Fiber Recipes repository](https://github.com/gofiber/recipes/tree/master/air). This example shows how to configure and use Air in a Fiber project to create an efficient development environment. - ## How do I set up an error handler? To override the default error handler, you can override the default when providing a [Config](../api/fiber.md#errorhandler) when initiating a new [Fiber instance](../api/fiber.md#new). @@ -92,78 +94,80 @@ To learn more about using Templates in Fiber, see [Templates](../guide/templates ## Does Fiber have a community chat? -Yes, we have our own [Discord ](https://gofiber.io/discord)server, where we hang out. We have different rooms for every subject. +Yes, we have our own [Discord](https://gofiber.io/discord)server, where we hang out. We have different rooms for every subject. If you have questions or just want to have a chat, feel free to join us via this **>** [**invite link**](https://gofiber.io/discord) **<**. ![](/img/support-discord.png) ## Does fiber support sub domain routing ? -Yes we do, here are some examples: +Yes we do, here are some examples: This example works v2 + ```go package main import ( - "log" + "log" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/logger" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/logger" ) type Host struct { - Fiber *fiber.App + Fiber *fiber.App } func main() { - // Hosts - hosts := map[string]*Host{} - //----- - // API - //----- - api := fiber.New() - api.Use(logger.New(logger.Config{ - Format: "[${ip}]:${port} ${status} - ${method} ${path}\n", - })) - hosts["api.localhost:3000"] = &Host{api} - api.Get("/", func(c fiber.Ctx) error { - return c.SendString("API") - }) - //------ - // Blog - //------ - blog := fiber.New() - blog.Use(logger.New(logger.Config{ - Format: "[${ip}]:${port} ${status} - ${method} ${path}\n", - })) - hosts["blog.localhost:3000"] = &Host{blog} - blog.Get("/", func(c fiber.Ctx) error { - return c.SendString("Blog") - }) - //--------- - // Website - //--------- - site := fiber.New() - site.Use(logger.New(logger.Config{ - Format: "[${ip}]:${port} ${status} - ${method} ${path}\n", - })) - - hosts["localhost:3000"] = &Host{site} - site.Get("/", func(c fiber.Ctx) error { - return c.SendString("Website") - }) - // Server - app := fiber.New() - app.Use(func(c fiber.Ctx) error { - host := hosts[c.Hostname()] - if host == nil { - return c.SendStatus(fiber.StatusNotFound) - } else { - host.Fiber.Handler()(c.Context()) - return nil - } - }) - log.Fatal(app.Listen(":3000")) + // Hosts + hosts := map[string]*Host{} + //----- + // API + //----- + api := fiber.New() + api.Use(logger.New(logger.Config{ + Format: "[${ip}]:${port} ${status} - ${method} ${path}\n", + })) + hosts["api.localhost:3000"] = &Host{api} + api.Get("/", func(c fiber.Ctx) error { + return c.SendString("API") + }) + //------ + // Blog + //------ + blog := fiber.New() + blog.Use(logger.New(logger.Config{ + Format: "[${ip}]:${port} ${status} - ${method} ${path}\n", + })) + hosts["blog.localhost:3000"] = &Host{blog} + blog.Get("/", func(c fiber.Ctx) error { + return c.SendString("Blog") + }) + //--------- + // Website + //--------- + site := fiber.New() + site.Use(logger.New(logger.Config{ + Format: "[${ip}]:${port} ${status} - ${method} ${path}\n", + })) + + hosts["localhost:3000"] = &Host{site} + site.Get("/", func(c fiber.Ctx) error { + return c.SendString("Website") + }) + // Server + app := fiber.New() + app.Use(func(c fiber.Ctx) error { + host := hosts[c.Hostname()] + if host == nil { + return c.SendStatus(fiber.StatusNotFound) + } else { + host.Fiber.Handler()(c.Context()) + return nil + } + }) + log.Fatal(app.Listen(":3000")) } ``` + If more information is needed, please refer to this issue [#750](https://github.com/gofiber/fiber/issues/750) diff --git a/docs/guide/error-handling.md b/docs/guide/error-handling.md index 584f28eda2..17fe4d7587 100644 --- a/docs/guide/error-handling.md +++ b/docs/guide/error-handling.md @@ -24,6 +24,7 @@ app.Get("/", func(c fiber.Ctx) error { return c.SendFile("file-does-not-exist") }) ``` + diff --git a/docs/guide/faster-fiber.md b/docs/guide/faster-fiber.md index d4c2df1b89..e1cf77a01f 100644 --- a/docs/guide/faster-fiber.md +++ b/docs/guide/faster-fiber.md @@ -5,7 +5,9 @@ sidebar_position: 7 --- ## Custom JSON Encoder/Decoder + Since Fiber v2.32.0, we use **encoding/json** as default json library due to stability and producibility. However, the standard library is a bit slow compared to 3rd party libraries. If you're not happy with the performance of **encoding/json**, we recommend you to use these libraries: + - [goccy/go-json](https://github.com/goccy/go-json) - [bytedance/sonic](https://github.com/bytedance/sonic) - [segmentio/encoding](https://github.com/segmentio/encoding) @@ -20,12 +22,12 @@ import "github.com/gofiber/fiber/v3" import "github.com/goccy/go-json" func main() { - app := fiber.New(fiber.Config{ - JSONEncoder: json.Marshal, - JSONDecoder: json.Unmarshal, - }) + app := fiber.New(fiber.Config{ + JSONEncoder: json.Marshal, + JSONDecoder: json.Unmarshal, + }) - # ... + # ... } ``` diff --git a/docs/guide/routing.md b/docs/guide/routing.md index 7dcc2b61e7..3badeac05f 100644 --- a/docs/guide/routing.md +++ b/docs/guide/routing.md @@ -20,7 +20,7 @@ import RoutingHandler from './../partials/routing/handler.md'; Route paths, combined with a request method, define the endpoints at which requests can be made. Route paths can be **strings** or **string patterns**. -**Examples of route paths based on strings** +### Examples of route paths based on strings ```go // This route path will match requests to the root route, "/": @@ -56,7 +56,7 @@ Greedy parameters are indicated by wildcard\(\*\) or plus\(+\) signs. The routing also offers the possibility to use optional parameters, for the named parameters these are marked with a final "?", unlike the plus sign which is not optional, you can use the wildcard character for a parameter range which is optional and greedy. -**Example of define routes with route parameters** +### Example of define routes with route parameters ```go // Parameters @@ -143,6 +143,7 @@ app.Get("/v1/*/shop/*", handler) We have adapted the routing strongly to the express routing, but currently without the possibility of the regular expressions, because they are quite slow. The possibilities can be tested with version 0.1.7 \(express 4\) in the online [Express route tester](http://forbeslindesay.github.io/express-route-tester/). ### Constraints + Route constraints execute when a match has occurred to the incoming URL and the URL path is tokenized into route values by parameters. The feature was introduced in `v2.37.0` and inspired by [.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-6.0#route-constraints). :::caution @@ -172,7 +173,7 @@ Constraints aren't validation for parameters. If constraints aren't valid for a ```go app.Get("/:test", func(c fiber.Ctx) error { - return c.SendString(c.Params("test")) + return c.SendString(c.Params("test")) }) // curl -X GET http://localhost:3000/12 @@ -181,13 +182,15 @@ app.Get("/:test", func(c fiber.Ctx) error { // curl -X GET http://localhost:3000/1 // Cannot GET /1 ``` + You can use `;` for multiple constraints. + ```go app.Get("/:test", func(c fiber.Ctx) error { - return c.SendString(c.Params("test")) + return c.SendString(c.Params("test")) }) // curl -X GET http://localhost:3000/120000 @@ -199,13 +202,15 @@ app.Get("/:test", func(c fiber.Ctx) error { // curl -X GET http://localhost:3000/250 // 250 ``` + Fiber precompiles regex query when to register routes. So there're no performance overhead for regex constraint. + ```go app.Get(`/:date`, func(c fiber.Ctx) error { - return c.SendString(c.Params("date")) + return c.SendString(c.Params("date")) }) // curl -X GET http://localhost:3000/125 @@ -245,21 +250,21 @@ app.Get("/:test?", func(c fiber.Ctx) error { Custom constraints can be added to Fiber using the `app.RegisterCustomConstraint` method. Your constraints have to be compatible with the `CustomConstraint` interface. -It is a good idea to add external constraints to your project once you want to add more specific rules to your routes. +It is a good idea to add external constraints to your project once you want to add more specific rules to your routes. For example, you can add a constraint to check if a parameter is a valid ULID. ```go // CustomConstraint is an interface for custom constraints type CustomConstraint interface { - // Name returns the name of the constraint. - // This name is used in the constraint matching. - Name() string - - // Execute executes the constraint. - // It returns true if the constraint is matched and right. - // param is the parameter value to check. - // args are the constraint arguments. - Execute(param string, args ...string) bool + // Name returns the name of the constraint. + // This name is used in the constraint matching. + Name() string + + // Execute executes the constraint. + // It returns true if the constraint is matched and right. + // param is the parameter value to check. + // args are the constraint arguments. + Execute(param string, args ...string) bool } ``` @@ -267,30 +272,30 @@ You can check the example below: ```go type UlidConstraint struct { - fiber.CustomConstraint + fiber.CustomConstraint } func (*UlidConstraint) Name() string { - return "ulid" + return "ulid" } func (*UlidConstraint) Execute(param string, args ...string) bool { - _, err := ulid.Parse(param) - return err == nil + _, err := ulid.Parse(param) + return err == nil } func main() { - app := fiber.New() - app.RegisterCustomConstraint(&UlidConstraint{}) + app := fiber.New() + app.RegisterCustomConstraint(&UlidConstraint{}) - app.Get("/login/:id", func(c fiber.Ctx) error { - return c.SendString("...") - }) + app.Get("/login/:id", func(c fiber.Ctx) error { + return c.SendString("...") + }) - app.Listen(":3000") + app.Listen(":3000") - // /login/01HK7H9ZE5BFMK348CPYP14S0Z -> 200 - // /login/12345 -> 404 + // /login/01HK7H9ZE5BFMK348CPYP14S0Z -> 200 + // /login/12345 -> 404 } ``` @@ -302,11 +307,11 @@ Functions that are designed to make changes to the request or response are calle ```go app.Use(func(c fiber.Ctx) error { - // Set a custom header on all responses: - c.Set("X-Custom-Header", "Hello, World") + // Set a custom header on all responses: + c.Set("X-Custom-Header", "Hello, World") - // Go to next middleware: - return c.Next() + // Go to next middleware: + return c.Next() }) app.Get("/", func(c fiber.Ctx) error { @@ -322,26 +327,25 @@ app.Get("/", func(c fiber.Ctx) error { Adding routes dynamically after the application has started is not supported due to design and performance considerations. Make sure to define all your routes before the application starts. ::: - ## Grouping If you have many endpoints, you can organize your routes using `Group`. ```go func main() { - app := fiber.New() + app := fiber.New() - api := app.Group("/api", middleware) // /api + api := app.Group("/api", middleware) // /api - v1 := api.Group("/v1", middleware) // /api/v1 - v1.Get("/list", handler) // /api/v1/list - v1.Get("/user", handler) // /api/v1/user + v1 := api.Group("/v1", middleware) // /api/v1 + v1.Get("/list", handler) // /api/v1/list + v1.Get("/user", handler) // /api/v1/user - v2 := api.Group("/v2", middleware) // /api/v2 - v2.Get("/list", handler) // /api/v2/list - v2.Get("/user", handler) // /api/v2/user + v2 := api.Group("/v2", middleware) // /api/v2 + v2.Get("/list", handler) // /api/v2/list + v2.Get("/user", handler) // /api/v2/user - log.Fatal(app.Listen(":3000")) + log.Fatal(app.Listen(":3000")) } ``` diff --git a/docs/guide/templates.md b/docs/guide/templates.md index 2bd441fe28..5aef7e61d2 100644 --- a/docs/guide/templates.md +++ b/docs/guide/templates.md @@ -21,6 +21,7 @@ type Views interface { Render(out io.Writer, name string, binding any, layout ...string) error } ``` + @@ -77,7 +78,7 @@ func main() { engine := html.New("./views", ".html") // If you want other engine, just replace with following // Create a new engine with django - // engine := django.New("./views", ".django") + // engine := django.New("./views", ".django") app := fiber.New(fiber.Config{ Views: engine, @@ -92,6 +93,7 @@ func main() { log.Fatal(app.Listen(":3000")) } ``` + @@ -102,5 +104,6 @@ func main() { ``` + diff --git a/docs/guide/utils.md b/docs/guide/utils.md index 3dbff1ab92..9d456237a7 100644 --- a/docs/guide/utils.md +++ b/docs/guide/utils.md @@ -33,7 +33,6 @@ app.Get("/search", func(c fiber.Ctx) error) { }) ``` - ### GetReqHeader GetReqHeader function utilizing Go's generics feature. diff --git a/docs/intro.md b/docs/intro.md index 9c651b38d6..2fd92a37fd 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -54,10 +54,10 @@ We created a custom `CopyString` function that does the above and is available u ```go app.Get("/:foo", func(c fiber.Ctx) error { - // Variable is now immutable - result := utils.CopyString(c.Params("foo")) + // Variable is now immutable + result := utils.CopyString(c.Params("foo")) - // ... + // ... }) ``` @@ -65,13 +65,13 @@ Alternatively, you can also use the `Immutable` setting. It will make all values ```go app := fiber.New(fiber.Config{ - Immutable: true, + Immutable: true, }) ``` For more information, please check [**\#426**](https://github.com/gofiber/fiber/issues/426), [**\#185**](https://github.com/gofiber/fiber/issues/185) and [**\#3012**](https://github.com/gofiber/fiber/issues/3012). -### Hello, World! +### Hello, World Embedded below is essentially the most straightforward **Fiber** app you can create: @@ -81,13 +81,13 @@ package main import "github.com/gofiber/fiber/v3" func main() { - app := fiber.New() + app := fiber.New() - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") - }) + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Hello, World!") + }) - app.Listen(":3000") + app.Listen(":3000") } ``` @@ -115,48 +115,48 @@ app.Method(path string, ...func(fiber.Ctx) error) - `path` is a virtual path on the server - `func(fiber.Ctx) error` is a callback function containing the [Context](https://docs.gofiber.io/api/ctx) executed when the route is matched -**Simple route** +#### Simple route ```go // Respond with "Hello, World!" on root path, "/" app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") + return c.SendString("Hello, World!") }) ``` -**Parameters** +#### Parameters ```go // GET http://localhost:8080/hello%20world app.Get("/:value", func(c fiber.Ctx) error { - return c.SendString("value: " + c.Params("value")) - // => Get request with value: hello world + return c.SendString("value: " + c.Params("value")) + // => Get request with value: hello world }) ``` -**Optional parameter** +#### Optional parameter ```go // GET http://localhost:3000/john app.Get("/:name?", func(c fiber.Ctx) error { - if c.Params("name") != "" { - return c.SendString("Hello " + c.Params("name")) - // => Hello john - } - return c.SendString("Where is john?") + if c.Params("name") != "" { + return c.SendString("Hello " + c.Params("name")) + // => Hello john + } + return c.SendString("Where is john?") }) ``` -**Wildcards** +#### Wildcards ```go // GET http://localhost:3000/api/user/john app.Get("/api/*", func(c fiber.Ctx) error { - return c.SendString("API path: " + c.Params("*")) - // => API path: user/john + return c.SendString("API path: " + c.Params("*")) + // => API path: user/john }) ``` diff --git a/docs/middleware/adaptor.md b/docs/middleware/adaptor.md index 39fc1895af..3103635d4b 100644 --- a/docs/middleware/adaptor.md +++ b/docs/middleware/adaptor.md @@ -7,6 +7,7 @@ id: adaptor Converter for net/http handlers to/from Fiber request handlers, special thanks to [@arsmn](https://github.com/arsmn)! ## Signatures + | Name | Signature | Description | :--- | :--- | :--- | HTTPHandler | `HTTPHandler(h http.Handler) fiber.Handler` | http.Handler -> fiber.Handler @@ -21,149 +22,154 @@ Converter for net/http handlers to/from Fiber request handlers, special thanks t ## Examples ### net/http to Fiber + ```go package main import ( - "fmt" - "net/http" + "fmt" + "net/http" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/adaptor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" ) func main() { - // New fiber app - app := fiber.New() + // New fiber app + app := fiber.New() - // http.Handler -> fiber.Handler - app.Get("/", adaptor.HTTPHandler(handler(greet))) + // http.Handler -> fiber.Handler + app.Get("/", adaptor.HTTPHandler(handler(greet))) - // http.HandlerFunc -> fiber.Handler - app.Get("/func", adaptor.HTTPHandlerFunc(greet)) + // http.HandlerFunc -> fiber.Handler + app.Get("/func", adaptor.HTTPHandlerFunc(greet)) - // Listen on port 3000 - app.Listen(":3000") + // Listen on port 3000 + app.Listen(":3000") } func handler(f http.HandlerFunc) http.Handler { - return http.HandlerFunc(f) + return http.HandlerFunc(f) } func greet(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "Hello World!") + fmt.Fprint(w, "Hello World!") } ``` ### net/http middleware to Fiber + ```go package main import ( - "log" - "net/http" + "log" + "net/http" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/adaptor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" ) func main() { - // New fiber app - app := fiber.New() + // New fiber app + app := fiber.New() - // http middleware -> fiber.Handler - app.Use(adaptor.HTTPMiddleware(logMiddleware)) + // http middleware -> fiber.Handler + app.Use(adaptor.HTTPMiddleware(logMiddleware)) - // Listen on port 3000 - app.Listen(":3000") + // Listen on port 3000 + app.Listen(":3000") } func logMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Println("log middleware") - next.ServeHTTP(w, r) - }) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println("log middleware") + next.ServeHTTP(w, r) + }) } ``` ### Fiber Handler to net/http + ```go package main import ( - "net/http" + "net/http" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/adaptor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" ) func main() { - // fiber.Handler -> http.Handler - http.Handle("/", adaptor.FiberHandler(greet)) + // fiber.Handler -> http.Handler + http.Handle("/", adaptor.FiberHandler(greet)) - // fiber.Handler -> http.HandlerFunc - http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet)) + // fiber.Handler -> http.HandlerFunc + http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet)) - // Listen on port 3000 - http.ListenAndServe(":3000", nil) + // Listen on port 3000 + http.ListenAndServe(":3000", nil) } func greet(c fiber.Ctx) error { - return c.SendString("Hello World!") + return c.SendString("Hello World!") } ``` ### Fiber App to net/http + ```go package main import ( - "net/http" + "net/http" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/adaptor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" ) func main() { - app := fiber.New() + app := fiber.New() - app.Get("/greet", greet) + app.Get("/greet", greet) - // Listen on port 3000 - http.ListenAndServe(":3000", adaptor.FiberApp(app)) + // Listen on port 3000 + http.ListenAndServe(":3000", adaptor.FiberApp(app)) } func greet(c fiber.Ctx) error { - return c.SendString("Hello World!") + return c.SendString("Hello World!") } ``` ### Fiber Context to (net/http).Request + ```go package main import ( - "net/http" + "net/http" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/adaptor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" ) func main() { - app := fiber.New() + app := fiber.New() - app.Get("/greet", greetWithHTTPReq) + app.Get("/greet", greetWithHTTPReq) - // Listen on port 3000 - http.ListenAndServe(":3000", adaptor.FiberApp(app)) + // Listen on port 3000 + http.ListenAndServe(":3000", adaptor.FiberApp(app)) } func greetWithHTTPReq(c fiber.Ctx) error { - httpReq, err := adaptor.ConvertRequest(c, false) - if err != nil { - return err - } + httpReq, err := adaptor.ConvertRequest(c, false) + if err != nil { + return err + } - return c.SendString("Request URL: " + httpReq.URL.String()) + return c.SendString("Request URL: " + httpReq.URL.String()) } ``` diff --git a/docs/middleware/cache.md b/docs/middleware/cache.md index f62ab9ff25..0723c615dc 100644 --- a/docs/middleware/cache.md +++ b/docs/middleware/cache.md @@ -52,7 +52,7 @@ app.Use(cache.New(cache.Config{ return time.Second * time.Duration(newCacheTime) }, KeyGenerator: func(c fiber.Ctx) string { - return utils.CopyString(c.Path()) + return utils.CopyString(c.Path()) }, })) diff --git a/docs/middleware/cors.md b/docs/middleware/cors.md index 4442d4b43f..3dfe04e3f7 100644 --- a/docs/middleware/cors.md +++ b/docs/middleware/cors.md @@ -86,7 +86,7 @@ func dbCheckOrigin(db *sql.DB, origin string) bool { app.Use(cors.New(cors.Config{ AllowOriginsFunc: func(origin string) bool { - return dbCheckOrigin(db, origin) + return dbCheckOrigin(db, origin) }, })) ``` @@ -104,7 +104,7 @@ app.Use(cors.New(cors.Config{ This will result in the following panic: -``` +```text panic: [CORS] Configuration error: When 'AllowCredentials' is set to true, 'AllowOrigins' cannot contain a wildcard origin '*'. Please specify allowed origins explicitly or adjust 'AllowCredentials' setting. ``` @@ -130,22 +130,22 @@ If AllowOrigins is a zero value `[]string{}`, and AllowOriginsFunc is provided, ```go var ConfigDefault = Config{ - Next: nil, - AllowOriginsFunc: nil, - AllowOrigins: []string{"*"}, - AllowMethods: []string{ - fiber.MethodGet, - fiber.MethodPost, - fiber.MethodHead, - fiber.MethodPut, - fiber.MethodDelete, - fiber.MethodPatch, - }, - AllowHeaders: []string{}, - AllowCredentials: false, - ExposeHeaders: []string{}, - MaxAge: 0, - AllowPrivateNetwork: false, + Next: nil, + AllowOriginsFunc: nil, + AllowOrigins: []string{"*"}, + AllowMethods: []string{ + fiber.MethodGet, + fiber.MethodPost, + fiber.MethodHead, + fiber.MethodPut, + fiber.MethodDelete, + fiber.MethodPatch, + }, + AllowHeaders: []string{}, + AllowCredentials: false, + ExposeHeaders: []string{}, + MaxAge: 0, + AllowPrivateNetwork: false, } ``` @@ -163,7 +163,7 @@ app.Use(cors.New(cors.Config{ })) ``` -# How It Works +## How It Works The CORS middleware works by adding the necessary CORS headers to responses from your Fiber application. These headers tell browsers what origins, methods, and headers are allowed for cross-origin requests. @@ -189,7 +189,7 @@ The `AllowMethods` option controls which HTTP methods are allowed. For example, The `AllowHeaders` option specifies which headers are allowed in the actual request. The middleware sets the Access-Control-Allow-Headers response header to the value of `AllowHeaders`. This informs the client which headers it can use in the actual request. -The `AllowCredentials` option indicates whether the response to the request can be exposed when the credentials flag is true. If `AllowCredentials` is set to `true`, the middleware adds the header `Access-Control-Allow-Credentials: true` to the response. To prevent security vulnerabilities, `AllowCredentials` cannot be set to `true` if `AllowOrigins` is set to a wildcard (`*`). +The `AllowCredentials` option indicates whether the response to the request can be exposed when the credentials flag is true. If `AllowCredentials` is set to `true`, the middleware adds the header `Access-Control-Allow-Credentials: true` to the response. To prevent security vulnerabilities, `AllowCredentials` cannot be set to `true` if `AllowOrigins` is set to a wildcard (`*`). The `ExposeHeaders` option defines a whitelist of headers that clients are allowed to access. If `ExposeHeaders` is set to `"X-Custom-Header"`, the middleware adds the header `Access-Control-Expose-Headers: X-Custom-Header` to the response. diff --git a/docs/middleware/csrf.md b/docs/middleware/csrf.md index 739802501c..a034f9dfd7 100644 --- a/docs/middleware/csrf.md +++ b/docs/middleware/csrf.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework: ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/csrf" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/csrf" ) ``` @@ -31,12 +31,12 @@ app.Use(csrf.New()) // Or extend your config for customization app.Use(csrf.New(csrf.Config{ - KeyLookup: "header:X-Csrf-Token", - CookieName: "csrf_", - CookieSameSite: "Lax", - Expiration: 1 * time.Hour, - KeyGenerator: utils.UUIDv4, - Extractor: func(c fiber.Ctx) (string, error) { ... }, + KeyLookup: "header:X-Csrf-Token", + CookieName: "csrf_", + CookieSameSite: "Lax", + Expiration: 1 * time.Hour, + KeyGenerator: utils.UUIDv4, + Extractor: func(c fiber.Ctx) (string, error) { ... }, })) ``` @@ -48,27 +48,27 @@ Getting the CSRF token in a handler: ```go func handler(c fiber.Ctx) error { - handler := csrf.HandlerFromContext(c) - token := csrf.TokenFromContext(c) - if handler == nil { - panic("csrf middleware handler not registered") - } - cfg := handler.Config - if cfg == nil { - panic("csrf middleware handler has no config") - } - if !strings.Contains(cfg.KeyLookup, ":") { - panic("invalid KeyLookup format") - } - formKey := strings.Split(cfg.KeyLookup, ":")[1] - - tmpl := fmt.Sprintf(`
- - - -
`, formKey, token) - c.Set("Content-Type", "text/html") - return c.SendString(tmpl) + handler := csrf.HandlerFromContext(c) + token := csrf.TokenFromContext(c) + if handler == nil { + panic("csrf middleware handler not registered") + } + cfg := handler.Config + if cfg == nil { + panic("csrf middleware handler has no config") + } + if !strings.Contains(cfg.KeyLookup, ":") { + panic("invalid KeyLookup format") + } + formKey := strings.Split(cfg.KeyLookup, ":")[1] + + tmpl := fmt.Sprintf(`
+ + + +
`, formKey, token) + c.Set("Content-Type", "text/html") + return c.SendString(tmpl) } ``` @@ -78,11 +78,11 @@ There are two basic use cases for the CSRF middleware: 1. **Without Sessions**: This is the simplest way to use the middleware. It uses the Double Submit Cookie Pattern and does not require a user session. - - See GoFiber recipe [CSRF](https://github.com/gofiber/recipes/tree/master/csrf) for an example of using the CSRF middleware without a user session. + - See GoFiber recipe [CSRF](https://github.com/gofiber/recipes/tree/master/csrf) for an example of using the CSRF middleware without a user session. 2. **With Sessions**: This is generally considered more secure. It uses the Synchronizer Token Pattern and requires a user session, and the use of pre-session, which prevents login CSRF attacks. - - See GoFiber recipe [CSRF with Session](https://github.com/gofiber/recipes/tree/master/csrf-with-session) for an example of using the CSRF middleware with a user session. + - See GoFiber recipe [CSRF with Session](https://github.com/gofiber/recipes/tree/master/csrf-with-session) for an example of using the CSRF middleware with a user session. ## Signatures @@ -94,7 +94,6 @@ func HandlerFromContext(c fiber.Ctx) *Handler func (h *Handler) DeleteToken(c fiber.Ctx) error ``` - ## Config | Property | Type | Description | Default | @@ -122,14 +121,14 @@ func (h *Handler) DeleteToken(c fiber.Ctx) error ```go var ConfigDefault = Config{ - KeyLookup: "header:" + HeaderName, - CookieName: "csrf_", - CookieSameSite: "Lax", - Expiration: 1 * time.Hour, - KeyGenerator: utils.UUIDv4, - ErrorHandler: defaultErrorHandler, - Extractor: FromHeader(HeaderName), - SessionKey: "csrfToken", + KeyLookup: "header:" + HeaderName, + CookieName: "csrf_", + CookieSameSite: "Lax", + Expiration: 1 * time.Hour, + KeyGenerator: utils.UUIDv4, + ErrorHandler: defaultErrorHandler, + Extractor: FromHeader(HeaderName), + SessionKey: "csrfToken", } ``` @@ -139,18 +138,18 @@ It's recommended to use this middleware with [fiber/middleware/session](https:// ```go var ConfigDefault = Config{ - KeyLookup: "header:" + HeaderName, - CookieName: "__Host-csrf_", - CookieSameSite: "Lax", - CookieSecure: true, - CookieSessionOnly: true, - CookieHTTPOnly: true, - Expiration: 1 * time.Hour, - KeyGenerator: utils.UUIDv4, - ErrorHandler: defaultErrorHandler, - Extractor: FromHeader(HeaderName), - Session: session.Store, - SessionKey: "csrfToken", + KeyLookup: "header:" + HeaderName, + CookieName: "__Host-csrf_", + CookieSameSite: "Lax", + CookieSecure: true, + CookieSessionOnly: true, + CookieHTTPOnly: true, + Expiration: 1 * time.Hour, + KeyGenerator: utils.UUIDv4, + ErrorHandler: defaultErrorHandler, + Extractor: FromHeader(HeaderName), + Session: session.Store, + SessionKey: "csrfToken", } ``` @@ -166,7 +165,7 @@ In the following example, the CSRF middleware will allow requests from `trusted. ```go app.Use(csrf.New(csrf.Config{ - TrustedOrigins: []string{"https://trusted.example.com"}, + TrustedOrigins: []string{"https://trusted.example.com"}, })) ``` @@ -176,7 +175,7 @@ In the following example, the CSRF middleware will allow requests from any subdo ```go app.Use(csrf.New(csrf.Config{ - TrustedOrigins: []string{"https://*.example.com"}, + TrustedOrigins: []string{"https://*.example.com"}, })) ``` @@ -216,19 +215,19 @@ Example, returning a JSON response for API requests and rendering an error page ```go app.Use(csrf.New(csrf.Config{ - ErrorHandler: func(c fiber.Ctx, err error) error { - accepts := c.Accepts("html", "json") - path := c.Path() - if accepts == "json" || strings.HasPrefix(path, "/api/") { - return c.Status(fiber.StatusForbidden).JSON(fiber.Map{ - "error": "Forbidden", - }) - } - return c.Status(fiber.StatusForbidden).Render("error", fiber.Map{ - "Title": "Forbidden", - "Status": fiber.StatusForbidden, - }, "layouts/main") - }, + ErrorHandler: func(c fiber.Ctx, err error) error { + accepts := c.Accepts("html", "json") + path := c.Path() + if accepts == "json" || strings.HasPrefix(path, "/api/") { + return c.Status(fiber.StatusForbidden).JSON(fiber.Map{ + "error": "Forbidden", + }) + } + return c.Status(fiber.StatusForbidden).Render("error", fiber.Map{ + "Title": "Forbidden", + "Status": fiber.StatusForbidden, + }, "layouts/main") + }, })) ``` @@ -239,17 +238,17 @@ You can use any storage from our [storage](https://github.com/gofiber/storage/) ```go storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3 app.Use(csrf.New(csrf.Config{ - Storage: storage, + Storage: storage, })) ``` -# How It Works +## How It Works -## Token Generation +### Token Generation CSRF tokens are generated on 'safe' requests and when the existing token has expired or hasn't been set yet. If `SingleUseToken` is `true`, a new token is generated after each use. Retrieve the CSRF token using `csrf.TokenFromContext(c)`. -## Security Considerations +### Security Considerations This middleware is designed to protect against CSRF attacks but does not protect against other attack vectors, such as XSS. It should be used in combination with other security measures. @@ -257,9 +256,9 @@ This middleware is designed to protect against CSRF attacks but does not protect Never use 'safe' methods to mutate data, for example, never use a GET request to modify a resource. This middleware will not protect against CSRF attacks on 'safe' methods. ::: -### Token Validation Patterns +## Token Validation Patterns -#### Double Submit Cookie Pattern (Default) +### Double Submit Cookie Pattern (Default) By default, the middleware generates and stores tokens using the `fiber.Storage` interface. These tokens are not linked to any particular user session, and they are validated using the Double Submit Cookie pattern. The token is stored in a cookie, and then sent as a header on requests. The middleware compares the cookie value with the header value to validate the token. This is a secure pattern that does not require a user session. @@ -273,7 +272,7 @@ When using this pattern, it's important to set the `CookieSameSite` option to `L When using this pattern, this middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for Storage saves data to memory. See [Custom Storage/Database](#custom-storagedatabase) for customizing the storage. ::: -#### Synchronizer Token Pattern (with Session) +### Synchronizer Token Pattern (with Session) When using this middleware with a user session, the middleware can be configured to store the token within the session. This method is recommended when using a user session, as it is generally more secure than the Double Submit Cookie Pattern. @@ -283,7 +282,7 @@ When using this pattern it's important to regenerate the session when the author Pre-sessions are required and will be created automatically if not present. Use a session value to indicate authentication instead of relying on the presence of a session. ::: -### Defense In Depth +## Defense In Depth When using this middleware, it's recommended to serve your pages over HTTPS, set the `CookieSecure` option to `true`, and set the `CookieSameSite` option to `Lax` or `Strict`. This ensures that the cookie is only sent over HTTPS and not on requests from external sites. @@ -293,7 +292,7 @@ Cookie prefixes `__Host-` and `__Secure-` can be used to further secure the cook To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secure-csrf_`. ::: -### Referer Checking +## Referer Checking For HTTPS requests, this middleware performs strict referer checking. Even if a subdomain can set or modify cookies on your domain, it can't force a user to post to your application, since that request won't come from your own exact domain. @@ -303,11 +302,11 @@ When HTTPS requests are protected by CSRF, referer checking is always carried ou The Referer header is automatically included in requests by all modern browsers, including those made using the JS Fetch API. However, if you're making use of this middleware with a custom client, it's important to ensure that the client sends a valid Referer header. ::: -### Token Lifecycle +## Token Lifecycle Tokens are valid until they expire or until they are deleted. By default, tokens are valid for 1 hour, and each subsequent request extends the expiration by 1 hour. The token only expires if the user doesn't make a request for the duration of the expiration time. -#### Token Reuse +### Token Reuse By default, tokens may be used multiple times. If you want to delete the token after it has been used, you can set the `SingleUseToken` option to `true`. This will delete the token after it has been used, and a new token will be generated on the next request. @@ -315,16 +314,16 @@ By default, tokens may be used multiple times. If you want to delete the token a Using `SingleUseToken` comes with usability trade-offs and is not enabled by default. For example, it can interfere with the user experience if the user has multiple tabs open or uses the back button. ::: -#### Deleting Tokens +### Deleting Tokens When the authorization status changes, the CSRF token MUST be deleted, and a new one generated. This can be done by calling `handler.DeleteToken(c)`. ```go handler := csrf.HandlerFromContext(ctx) if handler != nil { - if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { - // handle error - } + if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { + // handle error + } } ``` @@ -332,6 +331,6 @@ if handler != nil { If you are using this middleware with the fiber session middleware, then you can simply call `session.Destroy()`, `session.Regenerate()`, or `session.Reset()` to delete the session and the token stored therein. ::: -### BREACH +## BREACH It's important to note that the token is sent as a header on every request. If you include the token in a page that is vulnerable to [BREACH](https://en.wikipedia.org/wiki/BREACH), an attacker may be able to extract the token. To mitigate this, ensure your pages are served over HTTPS, disable HTTP compression, and implement rate limiting for requests. diff --git a/docs/middleware/earlydata.md b/docs/middleware/earlydata.md index a5ce3219fc..dbf45aa9f3 100644 --- a/docs/middleware/earlydata.md +++ b/docs/middleware/earlydata.md @@ -11,8 +11,8 @@ Make sure to enable fiber's `EnableTrustedProxyCheck` config option before using Also be aware that enabling support for early data in your reverse proxy (e.g. nginx, as done with a simple `ssl_early_data on;`) makes requests replayable. Refer to the following documents before continuing: -- https://datatracker.ietf.org/doc/html/rfc8446#section-8 -- https://blog.trailofbits.com/2019/03/25/what-application-developers-need-to-know-about-tls-early-data-0rtt/ +- +- By default, this middleware allows early data requests on safe HTTP request methods only and rejects the request otherwise, i.e. aborts the request before executing your handler. This behavior can be controlled by the `AllowEarlyData` config option. Safe HTTP methods — `GET`, `HEAD`, `OPTIONS` and `TRACE` — should not modify a state on the server. @@ -30,8 +30,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/earlydata" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/earlydata" ) ``` @@ -43,8 +43,8 @@ app.Use(earlydata.New()) // Or extend your config for customization app.Use(earlydata.New(earlydata.Config{ - Error: fiber.ErrTooEarly, - // ... + Error: fiber.ErrTooEarly, + // ... })) ``` @@ -61,13 +61,13 @@ app.Use(earlydata.New(earlydata.Config{ ```go var ConfigDefault = Config{ - IsEarlyData: func(c fiber.Ctx) bool { - return c.Get(DefaultHeaderName) == DefaultHeaderTrueValue - }, - AllowEarlyData: func(c fiber.Ctx) bool { - return fiber.IsMethodSafe(c.Method()) - }, - Error: fiber.ErrTooEarly, + IsEarlyData: func(c fiber.Ctx) bool { + return c.Get(DefaultHeaderName) == DefaultHeaderTrueValue + }, + AllowEarlyData: func(c fiber.Ctx) bool { + return fiber.IsMethodSafe(c.Method()) + }, + Error: fiber.ErrTooEarly, } ``` @@ -75,7 +75,7 @@ var ConfigDefault = Config{ ```go const ( - DefaultHeaderName = "Early-Data" - DefaultHeaderTrueValue = "1" + DefaultHeaderName = "Early-Data" + DefaultHeaderTrueValue = "1" ) ``` diff --git a/docs/middleware/encryptcookie.md b/docs/middleware/encryptcookie.md index 3054becb84..4fd565800a 100644 --- a/docs/middleware/encryptcookie.md +++ b/docs/middleware/encryptcookie.md @@ -4,7 +4,7 @@ id: encryptcookie # Encrypt Cookie -Encrypt Cookie is a middleware for [Fiber](https://github.com/gofiber/fiber) that secures your cookie values through encryption. +Encrypt Cookie is a middleware for [Fiber](https://github.com/gofiber/fiber) that secures your cookie values through encryption. :::note This middleware encrypts cookie values and not the cookie names. @@ -75,11 +75,11 @@ To generate a 32 char key, use `openssl rand -base64 32` or `encryptcookie.Gener ```go var ConfigDefault = Config{ - Next: nil, - Except: []string{}, - Key: "", - Encryptor: EncryptCookie, - Decryptor: DecryptCookie, + Next: nil, + Except: []string{}, + Key: "", + Encryptor: EncryptCookie, + Decryptor: DecryptCookie, } ``` @@ -91,20 +91,21 @@ You may also choose to exclude certain cookies from encryption. For instance, if ```go app.Use(encryptcookie.New(encryptcookie.Config{ - Key: "secret-thirty-2-character-string", - Except: []string{csrf.ConfigDefault.CookieName}, // exclude CSRF cookie + Key: "secret-thirty-2-character-string", + Except: []string{csrf.ConfigDefault.CookieName}, // exclude CSRF cookie })) app.Use(csrf.New(csrf.Config{ - KeyLookup: "header:" + csrf.HeaderName, - CookieSameSite: "Lax", - CookieSecure: true, - CookieHTTPOnly: false, + KeyLookup: "header:" + csrf.HeaderName, + CookieSameSite: "Lax", + CookieSecure: true, + CookieHTTPOnly: false, })) ``` ## Encryption Algorithms The default Encryptor and Decryptor functions use `AES-256-GCM` for encryption and decryption. If you need to use `AES-128` or `AES-192` instead, you can do so by changing the length of the key when calling `encryptcookie.GenerateKey(length)` or by providing a key of one of the following lengths: + - AES-128 requires a 16-byte key. - AES-192 requires a 24-byte key. - AES-256 requires a 32-byte key. @@ -119,4 +120,4 @@ And for AES-192: ```go key := encryptcookie.GenerateKey(24) -``` \ No newline at end of file +``` diff --git a/docs/middleware/envvar.md b/docs/middleware/envvar.md index 3740c38a9f..4467b7349d 100644 --- a/docs/middleware/envvar.md +++ b/docs/middleware/envvar.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/envvar" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/envvar" ) ``` @@ -31,10 +31,10 @@ app.Use("/expose/envvars", envvar.New()) // Or extend your config for customization app.Use("/expose/envvars", envvar.New( - envvar.Config{ - ExportVars: map[string]string{"testKey": "", "testDefaultKey": "testDefaultVal"}, - ExcludeVars: map[string]string{"excludeKey": ""}, - }), + envvar.Config{ + ExportVars: map[string]string{"testKey": "", "testDefaultKey": "testDefaultVal"}, + ExcludeVars: map[string]string{"excludeKey": ""}, + }), ) ``` @@ -45,7 +45,8 @@ You will need to provide a path to use the envvar middleware. ## Response Http response contract: -``` + +```json { "vars": { "someEnvVariable": "someValue", diff --git a/docs/middleware/expvar.md b/docs/middleware/expvar.md index 8299b8fd44..98c74abb51 100644 --- a/docs/middleware/expvar.md +++ b/docs/middleware/expvar.md @@ -24,6 +24,7 @@ import ( ``` After you initiate your Fiber app, you can use the following possibilities: + ```go var count = expvar.NewInt("count") diff --git a/docs/middleware/favicon.md b/docs/middleware/favicon.md index ddb0a7a7dd..7b1b66ca5b 100644 --- a/docs/middleware/favicon.md +++ b/docs/middleware/favicon.md @@ -55,9 +55,9 @@ app.Use(favicon.New(favicon.Config{ ```go var ConfigDefault = Config{ - Next: nil, - File: "", - URL: fPath, - CacheControl: "public, max-age=31536000", + Next: nil, + File: "", + URL: fPath, + CacheControl: "public, max-age=31536000", } ``` diff --git a/docs/middleware/healthcheck.md b/docs/middleware/healthcheck.md index d99e08517f..d92e6cffa9 100644 --- a/docs/middleware/healthcheck.md +++ b/docs/middleware/healthcheck.md @@ -29,6 +29,7 @@ func NewHealthChecker(config Config) fiber.Handler ## Examples Import the middleware package that is part of the [Fiber](https://github.com/gofiber/fiber) web framework + ```go import( "github.com/gofiber/fiber/v3" @@ -79,29 +80,30 @@ app.All(healthcheck.DefaultReadinessEndpoint, healthcheck.NewHealthChecker(healt ```go type Config struct { - // Next defines a function to skip this middleware when returned true. If this function returns true + // Next defines a function to skip this middleware when returned true. If this function returns true // and no other handlers are defined for the route, Fiber will return a status 404 Not Found, since // no other handlers were defined to return a different status. - // - // Optional. Default: nil - Next func(fiber.Ctx) bool - - // Function used for checking the liveness of the application. Returns true if the application - // is running and false if it is not. The liveness probe is typically used to indicate if - // the application is in a state where it can handle requests (e.g., the server is up and running). - // - // Optional. Default: func(c fiber.Ctx) bool { return true } - Probe HealthChecker + // + // Optional. Default: nil + Next func(fiber.Ctx) bool + + // Function used for checking the liveness of the application. Returns true if the application + // is running and false if it is not. The liveness probe is typically used to indicate if + // the application is in a state where it can handle requests (e.g., the server is up and running). + // + // Optional. Default: func(c fiber.Ctx) bool { return true } + Probe HealthChecker } ``` ## Default Config The default configuration used by this middleware is defined as follows: + ```go func defaultProbe(fiber.Ctx) bool { return true } var ConfigDefault = Config{ - Probe: defaultProbe, + Probe: defaultProbe, } ``` diff --git a/docs/middleware/helmet.md b/docs/middleware/helmet.md index b0dca52d54..37838bbf10 100644 --- a/docs/middleware/helmet.md +++ b/docs/middleware/helmet.md @@ -13,6 +13,7 @@ func New(config ...Config) fiber.Handler ``` ## Examples + ```go package main @@ -67,16 +68,16 @@ curl -I http://localhost:3000 ```go var ConfigDefault = Config{ - XSSProtection: "0", - ContentTypeNosniff: "nosniff", - XFrameOptions: "SAMEORIGIN", - ReferrerPolicy: "no-referrer", - CrossOriginEmbedderPolicy: "require-corp", - CrossOriginOpenerPolicy: "same-origin", - CrossOriginResourcePolicy: "same-origin", - OriginAgentCluster: "?1", - XDNSPrefetchControl: "off", - XDownloadOptions: "noopen", - XPermittedCrossDomain: "none", + XSSProtection: "0", + ContentTypeNosniff: "nosniff", + XFrameOptions: "SAMEORIGIN", + ReferrerPolicy: "no-referrer", + CrossOriginEmbedderPolicy: "require-corp", + CrossOriginOpenerPolicy: "same-origin", + CrossOriginResourcePolicy: "same-origin", + OriginAgentCluster: "?1", + XDNSPrefetchControl: "off", + XDownloadOptions: "noopen", + XPermittedCrossDomain: "none", } ``` diff --git a/docs/middleware/idempotency.md b/docs/middleware/idempotency.md index 475ec9dfc3..6f5c85f738 100644 --- a/docs/middleware/idempotency.md +++ b/docs/middleware/idempotency.md @@ -6,7 +6,7 @@ id: idempotency Idempotency middleware for [Fiber](https://github.com/gofiber/fiber) allows for fault-tolerant APIs where duplicate requests — for example due to networking issues on the client-side — do not erroneously cause the same action performed multiple times on the server-side. -Refer to https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header-02 for a better understanding. +Refer to for a better understanding. ## Signatures @@ -22,8 +22,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/idempotency" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/idempotency" ) ``` @@ -39,8 +39,8 @@ app.Use(idempotency.New()) ```go app.Use(idempotency.New(idempotency.Config{ - Lifetime: 42 * time.Minute, - // ... + Lifetime: 42 * time.Minute, + // ... })) ``` @@ -60,26 +60,26 @@ app.Use(idempotency.New(idempotency.Config{ ```go var ConfigDefault = Config{ - Next: func(c fiber.Ctx) bool { - // Skip middleware if the request was done using a safe HTTP method - return fiber.IsMethodSafe(c.Method()) - }, + Next: func(c fiber.Ctx) bool { + // Skip middleware if the request was done using a safe HTTP method + return fiber.IsMethodSafe(c.Method()) + }, - Lifetime: 30 * time.Minute, + Lifetime: 30 * time.Minute, - KeyHeader: "X-Idempotency-Key", - KeyHeaderValidate: func(k string) error { - if l, wl := len(k), 36; l != wl { // UUID length is 36 chars - return fmt.Errorf("%w: invalid length: %d != %d", ErrInvalidIdempotencyKey, l, wl) - } + KeyHeader: "X-Idempotency-Key", + KeyHeaderValidate: func(k string) error { + if l, wl := len(k), 36; l != wl { // UUID length is 36 chars + return fmt.Errorf("%w: invalid length: %d != %d", ErrInvalidIdempotencyKey, l, wl) + } - return nil - }, + return nil + }, - KeepResponseHeaders: nil, + KeepResponseHeaders: nil, - Lock: nil, // Set in configDefault so we don't allocate data here. + Lock: nil, // Set in configDefault so we don't allocate data here. - Storage: nil, // Set in configDefault so we don't allocate data here. + Storage: nil, // Set in configDefault so we don't allocate data here. } ``` diff --git a/docs/middleware/keyauth.md b/docs/middleware/keyauth.md index 9907a5dabf..c373ee5080 100644 --- a/docs/middleware/keyauth.md +++ b/docs/middleware/keyauth.md @@ -19,40 +19,40 @@ func TokenFromContext(c fiber.Ctx) string package main import ( - "crypto/sha256" - "crypto/subtle" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/keyauth" + "crypto/sha256" + "crypto/subtle" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/keyauth" ) var ( - apiKey = "correct horse battery staple" + apiKey = "correct horse battery staple" ) func validateAPIKey(c fiber.Ctx, key string) (bool, error) { - hashedAPIKey := sha256.Sum256([]byte(apiKey)) - hashedKey := sha256.Sum256([]byte(key)) + hashedAPIKey := sha256.Sum256([]byte(apiKey)) + hashedKey := sha256.Sum256([]byte(key)) - if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { - return true, nil - } - return false, keyauth.ErrMissingOrMalformedAPIKey + if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { + return true, nil + } + return false, keyauth.ErrMissingOrMalformedAPIKey } func main() { - app := fiber.New() + app := fiber.New() - // note that the keyauth middleware needs to be defined before the routes are defined! - app.Use(keyauth.New(keyauth.Config{ - KeyLookup: "cookie:access_token", - Validator: validateAPIKey, - })) + // note that the keyauth middleware needs to be defined before the routes are defined! + app.Use(keyauth.New(keyauth.Config{ + KeyLookup: "cookie:access_token", + Validator: validateAPIKey, + })) - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Successfully authenticated!") - }) + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Successfully authenticated!") + }) - app.Listen(":3000") + app.Listen(":3000") } ``` @@ -72,7 +72,6 @@ curl --cookie "access_token=Clearly A Wrong Key" http://localhost:3000 For a more detailed example, see also the [`github.com/gofiber/recipes`](https://github.com/gofiber/recipes) repository and specifically the `fiber-envoy-extauthz` repository and the [`keyauth example`](https://github.com/gofiber/recipes/blob/master/fiber-envoy-extauthz/authz/main.go) code. - ### Authenticate only certain endpoints If you want to authenticate only certain endpoints, you can use the `Config` of keyauth and apply a filter function (eg. `authFilter`) like so @@ -81,63 +80,63 @@ If you want to authenticate only certain endpoints, you can use the `Config` of package main import ( - "crypto/sha256" - "crypto/subtle" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/keyauth" - "regexp" - "strings" + "crypto/sha256" + "crypto/subtle" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/keyauth" + "regexp" + "strings" ) var ( - apiKey = "correct horse battery staple" - protectedURLs = []*regexp.Regexp{ - regexp.MustCompile("^/authenticated$"), - regexp.MustCompile("^/auth2$"), - } + apiKey = "correct horse battery staple" + protectedURLs = []*regexp.Regexp{ + regexp.MustCompile("^/authenticated$"), + regexp.MustCompile("^/auth2$"), + } ) func validateAPIKey(c fiber.Ctx, key string) (bool, error) { - hashedAPIKey := sha256.Sum256([]byte(apiKey)) - hashedKey := sha256.Sum256([]byte(key)) + hashedAPIKey := sha256.Sum256([]byte(apiKey)) + hashedKey := sha256.Sum256([]byte(key)) - if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { - return true, nil - } - return false, keyauth.ErrMissingOrMalformedAPIKey + if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { + return true, nil + } + return false, keyauth.ErrMissingOrMalformedAPIKey } func authFilter(c fiber.Ctx) bool { - originalURL := strings.ToLower(c.OriginalURL()) - - for _, pattern := range protectedURLs { - if pattern.MatchString(originalURL) { - return false - } - } - return true + originalURL := strings.ToLower(c.OriginalURL()) + + for _, pattern := range protectedURLs { + if pattern.MatchString(originalURL) { + return false + } + } + return true } func main() { - app := fiber.New() - - app.Use(keyauth.New(keyauth.Config{ - Next: authFilter, - KeyLookup: "cookie:access_token", - Validator: validateAPIKey, - })) - - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Welcome") - }) - app.Get("/authenticated", func(c fiber.Ctx) error { - return c.SendString("Successfully authenticated!") - }) - app.Get("/auth2", func(c fiber.Ctx) error { - return c.SendString("Successfully authenticated 2!") - }) - - app.Listen(":3000") + app := fiber.New() + + app.Use(keyauth.New(keyauth.Config{ + Next: authFilter, + KeyLookup: "cookie:access_token", + Validator: validateAPIKey, + })) + + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Welcome") + }) + app.Get("/authenticated", func(c fiber.Ctx) error { + return c.SendString("Successfully authenticated!") + }) + app.Get("/auth2", func(c fiber.Ctx) error { + return c.SendString("Successfully authenticated 2!") + }) + + app.Listen(":3000") } ``` @@ -163,10 +162,10 @@ curl --cookie "access_token=correct horse battery staple" http://localhost:3000/ package main import ( - "crypto/sha256" - "crypto/subtle" - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/keyauth" + "crypto/sha256" + "crypto/subtle" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/keyauth" ) const ( @@ -174,29 +173,29 @@ const ( ) func main() { - app := fiber.New() + app := fiber.New() - authMiddleware := keyauth.New(keyauth.Config{ - Validator: func(c fiber.Ctx, key string) (bool, error) { - hashedAPIKey := sha256.Sum256([]byte(apiKey)) - hashedKey := sha256.Sum256([]byte(key)) + authMiddleware := keyauth.New(keyauth.Config{ + Validator: func(c fiber.Ctx, key string) (bool, error) { + hashedAPIKey := sha256.Sum256([]byte(apiKey)) + hashedKey := sha256.Sum256([]byte(key)) - if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { - return true, nil - } - return false, keyauth.ErrMissingOrMalformedAPIKey - }, - }) + if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { + return true, nil + } + return false, keyauth.ErrMissingOrMalformedAPIKey + }, + }) - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Welcome") - }) + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Welcome") + }) - app.Get("/allowed", authMiddleware, func(c fiber.Ctx) error { - return c.SendString("Successfully authenticated!") - }) + app.Get("/allowed", authMiddleware, func(c fiber.Ctx) error { + return c.SendString("Successfully authenticated!") + }) - app.Listen(":3000") + app.Listen(":3000") } ``` @@ -228,23 +227,24 @@ curl --header "Authorization: Bearer my-super-secret-key" http://localhost:3000 ```go var ConfigDefault = Config{ - SuccessHandler: func(c fiber.Ctx) error { - return c.Next() - }, - ErrorHandler: func(c fiber.Ctx, err error) error { - if err == ErrMissingOrMalformedAPIKey { - return c.Status(fiber.StatusUnauthorized).SendString(err.Error()) - } - return c.Status(fiber.StatusUnauthorized).SendString("Invalid or expired API Key") - }, - KeyLookup: "header:" + fiber.HeaderAuthorization, - CustomKeyLookup: nil, - AuthScheme: "Bearer", + SuccessHandler: func(c fiber.Ctx) error { + return c.Next() + }, + ErrorHandler: func(c fiber.Ctx, err error) error { + if err == ErrMissingOrMalformedAPIKey { + return c.Status(fiber.StatusUnauthorized).SendString(err.Error()) + } + return c.Status(fiber.StatusUnauthorized).SendString("Invalid or expired API Key") + }, + KeyLookup: "header:" + fiber.HeaderAuthorization, + CustomKeyLookup: nil, + AuthScheme: "Bearer", } ``` ## CustomKeyLookup Two public utility functions are provided that may be useful when creating custom extraction: + * `DefaultKeyLookup(keyLookup string, authScheme string)`: This is the function that implements the default `KeyLookup` behavior, exposed to be used as a component of custom parsing logic * `MultipleKeySourceLookup(keyLookups []string, authScheme string)`: Creates a CustomKeyLookup function that checks each listed source using the above function until a key is found or the options are all exhausted. For example, `MultipleKeySourceLookup([]string{"header:Authorization", "header:x-api-key", "cookie:apikey"}, "Bearer")` would first check the standard Authorization header, checks the `x-api-key` header next, and finally checks for a cookie named `apikey`. If any of these contain a valid API key, the request continues. Otherwise, an error is returned. diff --git a/docs/middleware/limiter.md b/docs/middleware/limiter.md index 30986251c4..80574a8be8 100644 --- a/docs/middleware/limiter.md +++ b/docs/middleware/limiter.md @@ -26,8 +26,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/limiter" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/limiter" ) ``` @@ -69,7 +69,8 @@ app.Use(limiter.New(limiter.Config{ ``` This means that every window will take into account the previous window(if there was any). The given formula for the rate is: -``` + +```text weightOfPreviousWindpw = previous window's amount request * (whenNewWindow / Expiration) rate = weightOfPreviousWindpw + current window's amount request. ``` @@ -119,7 +120,8 @@ You can use any storage from our [storage](https://github.com/gofiber/storage/) ```go storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3 + app.Use(limiter.New(limiter.Config{ - Storage: storage, + Storage: storage, })) ``` diff --git a/docs/middleware/logger.md b/docs/middleware/logger.md index 7c147ba0dd..f9972ec200 100644 --- a/docs/middleware/logger.md +++ b/docs/middleware/logger.md @@ -7,9 +7,11 @@ id: logger Logger middleware for [Fiber](https://github.com/gofiber/fiber) that logs HTTP request/response details. ## Signatures + ```go func New(config ...Config) fiber.Handler ``` + ## Examples Import the middleware package that is part of the Fiber web framework @@ -88,7 +90,7 @@ app.Use(logger.New(logger.Config{ })) ``` -:::tip +:::tip Writing to os.File is goroutine-safe, but if you are using a custom Output that is not goroutine-safe, make sure to implement locking to properly serialize writes. ::: @@ -112,6 +114,7 @@ Writing to os.File is goroutine-safe, but if you are using a custom Output that | timeZoneLocation | `*time.Location` | Internal field for the time zone location. (This is not a user-configurable field) | - | ## Default Config + ```go var ConfigDefault = Config{ Next: nil, @@ -126,6 +129,7 @@ var ConfigDefault = Config{ ``` ## Constants + ```go // Logger variables const ( diff --git a/docs/middleware/monitor.md b/docs/middleware/monitor.md index b314c66bce..9c08a6bf02 100644 --- a/docs/middleware/monitor.md +++ b/docs/middleware/monitor.md @@ -14,22 +14,25 @@ Monitor is still in beta, API might change in the future! ![](https://i.imgur.com/nHAtBpJ.gif) -### Signatures +## Signatures + ```go func New() fiber.Handler ``` -### Examples +## Examples + Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/monitor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/monitor" ) ``` After you initiate your Fiber app, you can use the following possibilities: + ```go // Initialize default config (Assign the middleware to /metrics) app.Get("/metrics", monitor.New()) @@ -39,12 +42,22 @@ app.Get("/metrics", monitor.New()) // and change the Title to `MyService Metrics Page` app.Get("/metrics", monitor.New(monitor.Config{Title: "MyService Metrics Page"})) ``` + You can also access the API endpoint with `curl -X GET -H "Accept: application/json" http://localhost:3000/metrics` which returns: + ```json -{"pid":{ "cpu":0.4568381746582226, "ram":20516864, "conns":3 }, - "os": { "cpu":8.759124087593099, "ram":3997155328, "conns":44, - "total_ram":8245489664, "load_avg":0.51 }} +{ + "pid":{ + "cpu":0.4568381746582226, + "ram":20516864, + "conns":3 + }, + "os": { + "cpu":8.759124087593099, "ram":3997155328, "conns":44, + "total_ram":8245489664, "load_avg":0.51 + } +} ``` ## Config @@ -56,26 +69,26 @@ You can also access the API endpoint with | APIOnly | `bool` | Whether the service should expose only the monitoring API | false | | Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | | CustomHead | `string` | Custom HTML Code to Head Section(Before End) | empty | -| FontURL | `string` | FontURL for specify font resource path or URL | "https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap" | -| ChartJsURL | `string` | ChartJsURL for specify ChartJS library path or URL | "https://cdn.jsdelivr.net/npm/chart.js@2.9/dist/Chart.bundle.min.js" | +| FontURL | `string` | FontURL for specify font resource path or URL | "" | +| ChartJsURL | `string` | ChartJsURL for specify ChartJS library path or URL | "" | ## Default Config ```go var ConfigDefault = Config{ - Title: defaultTitle, - Refresh: defaultRefresh, - FontURL: defaultFontURL, - ChartJsURL: defaultChartJSURL, - CustomHead: defaultCustomHead, - APIOnly: false, - Next: nil, - index: newIndex(viewBag{ - defaultTitle, - defaultRefresh, - defaultFontURL, - defaultChartJSURL, - defaultCustomHead, - }), + Title: defaultTitle, + Refresh: defaultRefresh, + FontURL: defaultFontURL, + ChartJsURL: defaultChartJSURL, + CustomHead: defaultCustomHead, + APIOnly: false, + Next: nil, + index: newIndex(viewBag{ + defaultTitle, + defaultRefresh, + defaultFontURL, + defaultChartJSURL, + defaultCustomHead, + }), } ``` diff --git a/docs/middleware/proxy.md b/docs/middleware/proxy.md index 08d00b35c5..0045e6f07b 100644 --- a/docs/middleware/proxy.md +++ b/docs/middleware/proxy.md @@ -7,6 +7,7 @@ id: proxy Proxy middleware for [Fiber](https://github.com/gofiber/fiber) that allows you to proxy requests to multiple servers. ## Signatures + // BalancerForward performs the given http request based on a round-robin balancer and fills the given http response. ```go @@ -157,7 +158,7 @@ app.Use(proxy.Balancer(proxy.Config{ | Property | Type | Description | Default | |:----------------|:-----------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------| | Next | `func(fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | -| Servers | `[]string` | Servers defines a list of `://` HTTP servers, which are used in a round-robin manner. i.e.: "https://foobar.com, http://www.foobar.com" | (Required) | +| Servers | `[]string` | Servers defines a list of `://` HTTP servers, which are used in a round-robin manner. i.e.: ", " | (Required) | | ModifyRequest | `fiber.Handler` | ModifyRequest allows you to alter the request. | `nil` | | ModifyResponse | `fiber.Handler` | ModifyResponse allows you to alter the response. | `nil` | | Timeout | `time.Duration` | Timeout is the request timeout used when calling the proxy client. | 1 second | diff --git a/docs/middleware/redirect.md b/docs/middleware/redirect.md index c7976a7a0c..1c405499f1 100644 --- a/docs/middleware/redirect.md +++ b/docs/middleware/redirect.md @@ -63,6 +63,6 @@ curl http://localhost:3000/old/hello ```go var ConfigDefault = Config{ - StatusCode: fiber.StatusFound, + StatusCode: fiber.StatusFound, } ``` diff --git a/docs/middleware/requestid.md b/docs/middleware/requestid.md index 36abb20191..8af06056b1 100644 --- a/docs/middleware/requestid.md +++ b/docs/middleware/requestid.md @@ -58,6 +58,7 @@ func handler(c fiber.Ctx) error { | Generator | `func() string` | Generator defines a function to generate the unique identifier. | utils.UUID | ## Default Config + The default config uses a fast UUID generator which will expose the number of requests made to the server. To conceal this value for better privacy, use the `utils.UUIDv4` generator. @@ -66,6 +67,6 @@ requests made to the server. To conceal this value for better privacy, use the var ConfigDefault = Config{ Next: nil, Header: fiber.HeaderXRequestID, - Generator: utils.UUID, + Generator: utils.UUID, } ``` diff --git a/docs/middleware/rewrite.md b/docs/middleware/rewrite.md index d7ca4a223f..cb364bbad9 100644 --- a/docs/middleware/rewrite.md +++ b/docs/middleware/rewrite.md @@ -20,6 +20,7 @@ func New(config ...Config) fiber.Handler | Rules | `map[string]string` | Rules defines the URL path rewrite rules. The values captured in asterisk can be retrieved by index. | (Required) | ### Examples + ```go package main diff --git a/docs/middleware/session.md b/docs/middleware/session.md index db62b53cd4..0763b9dfb9 100644 --- a/docs/middleware/session.md +++ b/docs/middleware/session.md @@ -37,7 +37,9 @@ Storing `any` values are limited to built-ins Go types. ::: ## Examples + Import the middleware package that is part of the Fiber web framework + ```go import ( "github.com/gofiber/fiber/v3" @@ -76,15 +78,15 @@ app.Get("/", func(c fiber.Ctx) error { panic(err) } - // Sets a specific expiration for this session - sess.SetExpiry(time.Second * 2) + // Sets a specific expiration for this session + sess.SetExpiry(time.Second * 2) // Save session if err := sess.Save(); err != nil { - panic(err) - } + panic(err) + } - return c.SendString(fmt.Sprintf("Welcome %v", name)) + return c.SendString(fmt.Sprintf("Welcome %v", name)) }) ``` @@ -108,11 +110,11 @@ app.Get("/", func(c fiber.Ctx) error { ```go var ConfigDefault = Config{ - Expiration: 24 * time.Hour, - KeyLookup: "cookie:session_id", - KeyGenerator: utils.UUIDv4, - source: "cookie", - sessionName: "session_id", + Expiration: 24 * time.Hour, + KeyLookup: "cookie:session_id", + KeyGenerator: utils.UUIDv4, + source: "cookie", + sessionName: "session_id", } ``` @@ -120,9 +122,9 @@ var ConfigDefault = Config{ ```go const ( - SourceCookie Source = "cookie" - SourceHeader Source = "header" - SourceURLQuery Source = "query" + SourceCookie Source = "cookie" + SourceHeader Source = "header" + SourceURLQuery Source = "query" ) ``` @@ -133,7 +135,7 @@ You can use any storage from our [storage](https://github.com/gofiber/storage/) ```go storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3 store := session.New(session.Config{ - Storage: storage, + Storage: storage, }) ``` diff --git a/docs/middleware/skip.md b/docs/middleware/skip.md index 07df603bc9..a80bf8513b 100644 --- a/docs/middleware/skip.md +++ b/docs/middleware/skip.md @@ -7,12 +7,15 @@ id: skip Skip middleware for [Fiber](https://github.com/gofiber/fiber) that skips a wrapped handler if a predicate is true. ## Signatures + ```go func New(handler fiber.Handler, exclude func(c fiber.Ctx) bool) fiber.Handler ``` ## Examples + Import the middleware package that is part of the Fiber web framework + ```go import ( "github.com/gofiber/fiber/v3" @@ -24,21 +27,21 @@ After you initiate your Fiber app, you can use the following possibilities: ```go func main() { - app := fiber.New() + app := fiber.New() - app.Use(skip.New(BasicHandler, func(ctx fiber.Ctx) bool { - return ctx.Method() == fiber.MethodGet - })) + app.Use(skip.New(BasicHandler, func(ctx fiber.Ctx) bool { + return ctx.Method() == fiber.MethodGet + })) - app.Get("/", func(ctx fiber.Ctx) error { - return ctx.SendString("It was a GET request!") - }) + app.Get("/", func(ctx fiber.Ctx) error { + return ctx.SendString("It was a GET request!") + }) - log.Fatal(app.Listen(":3000")) + log.Fatal(app.Listen(":3000")) } func BasicHandler(ctx fiber.Ctx) error { - return ctx.SendString("It was not a GET request!") + return ctx.SendString("It was not a GET request!") } ``` diff --git a/docs/middleware/static.md b/docs/middleware/static.md index 6dd4e3cfe6..0a1d8a88aa 100644 --- a/docs/middleware/static.md +++ b/docs/middleware/static.md @@ -19,6 +19,7 @@ func New(root string, cfg ...Config) fiber.Handler ## Examples Import the middleware package that is part of the [Fiber](https://github.com/gofiber/fiber) web framework + ```go import( "github.com/gofiber/fiber/v3" diff --git a/docs/middleware/timeout.md b/docs/middleware/timeout.md index e5f77546a0..8f94f0567f 100644 --- a/docs/middleware/timeout.md +++ b/docs/middleware/timeout.md @@ -6,12 +6,11 @@ id: timeout There exist two distinct implementations of timeout middleware [Fiber](https://github.com/gofiber/fiber). -**New** +## New -As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` and pass it in `UserContext`. - -If the context passed executions (eg. DB ops, Http calls) takes longer than the given duration to return, the timeout error is set and forwarded to the centralized `ErrorHandler`. +As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` and pass it in `UserContext`. +If the context passed executions (eg. DB ops, Http calls) takes longer than the given duration to return, the timeout error is set and forwarded to the centralized `ErrorHandler`. It does not cancel long running executions. Underlying executions must handle timeout by using `context.Context` parameter. @@ -27,8 +26,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/timeout" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/timeout" ) ``` @@ -36,31 +35,31 @@ After you initiate your Fiber app, you can use the following possibilities: ```go func main() { - app := fiber.New() - h := func(c fiber.Ctx) error { - sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms") - if err := sleepWithContext(c.UserContext(), sleepTime); err != nil { - return fmt.Errorf("%w: execution error", err) - } - return nil - } - - app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second)) - log.Fatal(app.Listen(":3000")) + app := fiber.New() + h := func(c fiber.Ctx) error { + sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms") + if err := sleepWithContext(c.UserContext(), sleepTime); err != nil { + return fmt.Errorf("%w: execution error", err) + } + return nil + } + + app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second)) + log.Fatal(app.Listen(":3000")) } func sleepWithContext(ctx context.Context, d time.Duration) error { - timer := time.NewTimer(d) - - select { - case <-ctx.Done(): - if !timer.Stop() { - <-timer.C - } - return context.DeadlineExceeded - case <-timer.C: - } - return nil + timer := time.NewTimer(d) + + select { + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + return context.DeadlineExceeded + case <-timer.C: + } + return nil } ``` @@ -82,30 +81,30 @@ Use with custom error: var ErrFooTimeOut = errors.New("foo context canceled") func main() { - app := fiber.New() - h := func(c fiber.Ctx) error { - sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms") - if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil { - return fmt.Errorf("%w: execution error", err) - } - return nil - } - - app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second, ErrFooTimeOut)) - log.Fatal(app.Listen(":3000")) + app := fiber.New() + h := func(c fiber.Ctx) error { + sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms") + if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil { + return fmt.Errorf("%w: execution error", err) + } + return nil + } + + app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second, ErrFooTimeOut)) + log.Fatal(app.Listen(":3000")) } func sleepWithContextWithCustomError(ctx context.Context, d time.Duration) error { - timer := time.NewTimer(d) - select { - case <-ctx.Done(): - if !timer.Stop() { - <-timer.C - } - return ErrFooTimeOut - case <-timer.C: - } - return nil + timer := time.NewTimer(d) + select { + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + return ErrFooTimeOut + case <-timer.C: + } + return nil } ``` @@ -113,24 +112,24 @@ Sample usage with a DB call: ```go func main() { - app := fiber.New() - db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{}) - - handler := func(ctx fiber.Ctx) error { - tran := db.WithContext(ctx.UserContext()).Begin() - - if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil { - return tran.Error - } - - if tran = tran.Commit(); tran.Error != nil { - return tran.Error - } - - return nil - } - - app.Get("/foo", timeout.New(handler, 10*time.Second)) - log.Fatal(app.Listen(":3000")) + app := fiber.New() + db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{}) + + handler := func(ctx fiber.Ctx) error { + tran := db.WithContext(ctx.UserContext()).Begin() + + if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil { + return tran.Error + } + + if tran = tran.Commit(); tran.Error != nil { + return tran.Error + } + + return nil + } + + app.Get("/foo", timeout.New(handler, 10*time.Second)) + log.Fatal(app.Listen(":3000")) } ``` diff --git a/docs/whats_new.md b/docs/whats_new.md index 934d94c7a6..fd01c4a698 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -20,6 +20,7 @@ We are excited to announce the release of Fiber v3! 🚀 In this guide, we'll walk you through the most important changes in Fiber `v3` and show you how to migrate your existing Fiber `v2` applications to Fiber `v3`. Here's a quick overview of the changes in Fiber `v3`: + - [🚀 App](#-app) - [🗺️ Router](#-router) - [🧠 Context](#-context) @@ -46,33 +47,33 @@ DRAFT section We have made several changes to the Fiber app, including: -* Listen -> unified with config -* Static -> has been removed and moved to [static middleware](./middleware/static.md) -* app.Config properties moved to listen config - * DisableStartupMessage - * EnablePrefork -> previously Prefork - * EnablePrintRoutes - * ListenerNetwork -> previously Network +- Listen -> unified with config +- Static -> has been removed and moved to [static middleware](./middleware/static.md) +- app.Config properties moved to listen config + - DisableStartupMessage + - EnablePrefork -> previously Prefork + - EnablePrintRoutes + - ListenerNetwork -> previously Network ### new methods -* RegisterCustomBinder -* RegisterCustomConstraint -* NewCtxFunc +- RegisterCustomBinder +- RegisterCustomConstraint +- NewCtxFunc ### removed methods -* Mount -> Use app.Use() instead -* ListenTLS -> Use app.Listen() with tls.Config -* ListenTLSWithCertificate -> Use app.Listen() with tls.Config -* ListenMutualTLS -> Use app.Listen() with tls.Config -* ListenMutualTLSWithCertificate -> Use app.Listen() with tls.Config +- Mount -> Use app.Use() instead +- ListenTLS -> Use app.Listen() with tls.Config +- ListenTLSWithCertificate -> Use app.Listen() with tls.Config +- ListenMutualTLS -> Use app.Listen() with tls.Config +- ListenMutualTLSWithCertificate -> Use app.Listen() with tls.Config ### Methods changes -* Test -> timeout changed to 1 second -* Listen -> has a config parameter -* Listener -> has a config parameter +- Test -> timeout changed to 1 second +- Listen -> has a config parameter +- Listener -> has a config parameter ### CTX interface + customizable @@ -141,6 +142,7 @@ app.Route("/api").Route("/user/:id?") }) }) ``` +
[Here](./api/app#route) you can find more information. @@ -169,6 +171,7 @@ api.Get("/user", func(c *fiber.Ctx) error { // register subapp app.Use("/api", api) ``` +
To enable the routing changes above we had to slightly adjust the signature of the `Add` method. @@ -192,37 +195,37 @@ DRAFT section ### new methods -* AutoFormat -> ExpressJs like -* Host -> ExpressJs like -* Port -> ExpressJs like -* IsProxyTrusted -* Reset -* Schema -> ExpressJs like -* SendStream -> ExpressJs like -* SendString -> ExpressJs like -* String -> ExpressJs like -* ViewBind -> instead of Bind +- AutoFormat -> ExpressJs like +- Host -> ExpressJs like +- Port -> ExpressJs like +- IsProxyTrusted +- Reset +- Schema -> ExpressJs like +- SendStream -> ExpressJs like +- SendString -> ExpressJs like +- String -> ExpressJs like +- ViewBind -> instead of Bind ### removed methods -* AllParams -> c.Bind().URL() ? -* ParamsInt -> Params Generic -* QueryBool -> Query Generic -* QueryFloat -> Query Generic -* QueryInt -> Query Generic -* BodyParser -> c.Bind().Body() -* CookieParser -> c.Bind().Cookie() -* ParamsParser -> c.Bind().URL() -* RedirectToRoute -> c.Redirect().Route() -* RedirectBack -> c.Redirect().Back() -* ReqHeaderParser -> c.Bind().Header() +- AllParams -> c.Bind().URL() ? +- ParamsInt -> Params Generic +- QueryBool -> Query Generic +- QueryFloat -> Query Generic +- QueryInt -> Query Generic +- BodyParser -> c.Bind().Body() +- CookieParser -> c.Bind().Cookie() +- ParamsParser -> c.Bind().URL() +- RedirectToRoute -> c.Redirect().Route() +- RedirectBack -> c.Redirect().Back() +- ReqHeaderParser -> c.Bind().Header() ### changed methods -* Bind -> for Binding instead of View, us c.ViewBind() -* Format -> Param: body interface{} -> handlers ...ResFmt -* Redirect -> c.Redirect().To() -* SendFile now supports different configurations using the config parameter. +- Bind -> for Binding instead of View, us c.ViewBind() +- Format -> Param: body interface{} -> handlers ...ResFmt +- Redirect -> c.Redirect().To() +- SendFile now supports different configurations using the config parameter. --- @@ -230,7 +233,7 @@ DRAFT section The Gofiber client has been completely rebuilt. It includes numerous new features such as Cookiejar, request/response hooks, and more. You can take a look to [client docs](./client/rest.md) to see what's new with the client. - + ## 📎 Binding :::caution @@ -243,7 +246,6 @@ DRAFT section DRAFT section ::: - ## 🧰 Generic functions :::caution @@ -261,9 +263,11 @@ We are excited to introduce a new option in our caching middleware: Cache Invali We've made some changes to the CORS middleware to improve its functionality and flexibility. Here's what's new: #### New Struct Fields + - `Config.AllowPrivateNetwork`: This new field is a boolean that allows you to control whether private networks are allowed. This is related to the [Private Network Access (PNA)](https://wicg.github.io/private-network-access/) specification from the Web Incubator Community Group (WICG). When set to `true`, the CORS middleware will allow CORS preflight requests from private networks and respond with the `Access-Control-Allow-Private-Network: true` header. This could be useful in development environments or specific use cases, but should be done with caution due to potential security risks. #### Updated Struct Fields + We've updated several fields from a single string (containing comma-separated values) to slices, allowing for more explicit declaration of multiple values. Here are the updated fields: - `Config.AllowOrigins`: Now accepts a slice of strings, each representing an allowed origin. @@ -287,7 +291,7 @@ DRAFT section ### Filesystem -We've decided to remove filesystem middleware to clear up the confusion between static and filesystem middleware. +We've decided to remove filesystem middleware to clear up the confusion between static and filesystem middleware. Now, static middleware can do everything that filesystem middleware and static do. You can check out [static middleware](./middleware/static.md) or [migration guide](#-migration-guide) to see what has been changed. ### Monitor @@ -308,7 +312,6 @@ Monitor middleware is now in Contrib package. - [🌎 Client package](#-client-package-1) - [🧬 Middlewares](#-middlewares-1) - ### 🚀 App #### Static diff --git a/middleware/adaptor/README.md b/middleware/adaptor/README.md index abc0184a71..8bacab410a 100644 --- a/middleware/adaptor/README.md +++ b/middleware/adaptor/README.md @@ -1,20 +1,14 @@ # Adaptor -![Release](https://img.shields.io/github/release/gofiber/adaptor.svg) -[![Discord](https://img.shields.io/badge/discord-join%20channel-7289DA)](https://gofiber.io/discord) -![Test](https://github.com/gofiber/adaptor/workflows/Test/badge.svg) -![Security](https://github.com/gofiber/adaptor/workflows/Security/badge.svg) -![Linter](https://github.com/gofiber/adaptor/workflows/Linter/badge.svg) +## Install -Converter for net/http handlers to/from Fiber request handlers, special thanks to [@arsmn](https://github.com/arsmn)! - -### Install -``` +```bash go get -u github.com/gofiber/fiber/v3 -go get -u github.com/gofiber/adaptor/v2 +go get -u github.com/gofiber/fiber/middleware/adaptor ``` -### Functions +## Functions + | Name | Signature | Description | :--- | :--- | :--- | HTTPHandler | `HTTPHandler(h http.Handler) fiber.Handler` | http.Handler -> fiber.Handler @@ -24,118 +18,122 @@ go get -u github.com/gofiber/adaptor/v2 | FiberHandlerFunc | `FiberHandlerFunc(h fiber.Handler) http.HandlerFunc` | fiber.Handler -> http.HandlerFunc | FiberApp | `FiberApp(app *fiber.App) http.HandlerFunc` | Fiber app -> http.HandlerFunc -### net/http to Fiber +## net/http to Fiber + ```go package main import ( - "fmt" - "net/http" + "fmt" + "net/http" - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" + "github.com/gofiber/adaptor/v2" + "github.com/gofiber/fiber/v3" ) func main() { - // New fiber app - app := fiber.New() + // New fiber app + app := fiber.New() - // http.Handler -> fiber.Handler - app.Get("/", adaptor.HTTPHandler(handler(greet))) + // http.Handler -> fiber.Handler + app.Get("/", adaptor.HTTPHandler(handler(greet))) - // http.HandlerFunc -> fiber.Handler - app.Get("/func", adaptor.HTTPHandlerFunc(greet)) + // http.HandlerFunc -> fiber.Handler + app.Get("/func", adaptor.HTTPHandlerFunc(greet)) - // Listen on port 3000 - app.Listen(":3000") + // Listen on port 3000 + app.Listen(":3000") } func handler(f http.HandlerFunc) http.Handler { - return http.HandlerFunc(f) + return http.HandlerFunc(f) } func greet(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "Hello World!") + fmt.Fprint(w, "Hello World!") } ``` -### net/http middleware to Fiber +## net/http middleware to Fiber + ```go package main import ( - "log" - "net/http" + "log" + "net/http" - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" + "github.com/gofiber/adaptor/v2" + "github.com/gofiber/fiber/v3" ) func main() { - // New fiber app - app := fiber.New() + // New fiber app + app := fiber.New() - // http middleware -> fiber.Handler - app.Use(adaptor.HTTPMiddleware(logMiddleware)) + // http middleware -> fiber.Handler + app.Use(adaptor.HTTPMiddleware(logMiddleware)) - // Listen on port 3000 - app.Listen(":3000") + // Listen on port 3000 + app.Listen(":3000") } func logMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Println("log middleware") - next.ServeHTTP(w, r) - }) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println("log middleware") + next.ServeHTTP(w, r) + }) } ``` -### Fiber Handler to net/http +## Fiber Handler to net/http + ```go package main import ( - "net/http" + "net/http" - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" + "github.com/gofiber/adaptor/v2" + "github.com/gofiber/fiber/v3" ) func main() { - // fiber.Handler -> http.Handler - http.Handle("/", adaptor.FiberHandler(greet)) + // fiber.Handler -> http.Handler + http.Handle("/", adaptor.FiberHandler(greet)) - // fiber.Handler -> http.HandlerFunc - http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet)) + // fiber.Handler -> http.HandlerFunc + http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet)) - // Listen on port 3000 - http.ListenAndServe(":3000", nil) + // Listen on port 3000 + http.ListenAndServe(":3000", nil) } func greet(c fiber.Ctx) error { - return c.SendString("Hello World!") + return c.SendString("Hello World!") } ``` -### Fiber App to net/http +## Fiber App to net/http + ```go package main import ( - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" - "net/http" + "github.com/gofiber/adaptor/v2" + "github.com/gofiber/fiber/v3" + "net/http" ) func main() { - app := fiber.New() + app := fiber.New() - app.Get("/greet", greet) + app.Get("/greet", greet) - // Listen on port 3000 - http.ListenAndServe(":3000", adaptor.FiberApp(app)) + // Listen on port 3000 + http.ListenAndServe(":3000", adaptor.FiberApp(app)) } func greet(c fiber.Ctx) error { - return c.SendString("Hello World!") + return c.SendString("Hello World!") } ``` diff --git a/middleware/helmet/README.md b/middleware/helmet/README.md index 7cd99d0aef..e5724deef5 100644 --- a/middleware/helmet/README.md +++ b/middleware/helmet/README.md @@ -1,38 +1,37 @@ # Helmet -![Release](https://img.shields.io/github/release/gofiber/helmet.svg) -[![Discord](https://img.shields.io/badge/discord-join%20channel-7289DA)](https://gofiber.io/discord) -![Test](https://github.com/gofiber/helmet/workflows/Test/badge.svg) -![Security](https://github.com/gofiber/helmet/workflows/Security/badge.svg) -![Linter](https://github.com/gofiber/helmet/workflows/Linter/badge.svg) +## Install -### Install -``` +```bash go get -u github.com/gofiber/fiber/v3 -go get -u github.com/gofiber/helmet/v2 +go get -u github.com/gofiber/middleware/helmet ``` -### Example + +## Example + ```go package main import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/helmet/v2" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/helmet" ) func main() { - app := fiber.New() + app := fiber.New() - app.Use(helmet.New()) + app.Use(helmet.New()) - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Welcome!") - }) + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Welcome!") + }) - app.Listen(":3000") + app.Listen(":3000") } ``` -### Test -```curl + +## Test + +```bash curl -I http://localhost:3000 ``` diff --git a/middleware/keyauth/README.md b/middleware/keyauth/README.md index c4bd5814d2..734ad40244 100644 --- a/middleware/keyauth/README.md +++ b/middleware/keyauth/README.md @@ -1,44 +1,41 @@ # Key Authentication -![Release](https://img.shields.io/github/release/gofiber/keyauth.svg) -[![Discord](https://img.shields.io/badge/discord-join%20channel-7289DA)](https://gofiber.io/discord) -![Test](https://github.com/gofiber/keyauth/workflows/Test/badge.svg) -![Security](https://github.com/gofiber/keyauth/workflows/Security/badge.svg) -![Linter](https://github.com/gofiber/keyauth/workflows/Linter/badge.svg) +## Install -Special thanks to [József Sallai](https://github.com/jozsefsallai) & [Ray Mayemir](https://github.com/raymayemir) - -### Install -``` +```bash go get -u github.com/gofiber/fiber/v3 go get -u github.com/gofiber/keyauth/v2 ``` -### Example + +## Example + ```go package main import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/keyauth/v2" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/middleware/keyauth" ) func main() { - app := fiber.New() - - app.Use(keyauth.New(keyauth.Config{ - KeyLookup: "cookie:access_token", - ContextKey: "my_token", - })) - - app.Get("/", func(c fiber.Ctx) error { - token := c.TokenFromContext(c) // "" is returned if not found - return c.SendString(token) - }) - - app.Listen(":3000") + app := fiber.New() + + app.Use(keyauth.New(keyauth.Config{ + KeyLookup: "cookie:access_token", + ContextKey: "my_token", + })) + + app.Get("/", func(c fiber.Ctx) error { + token := c.TokenFromContext(c) // "" is returned if not found + return c.SendString(token) + }) + + app.Listen(":3000") } ``` -### Test -```curl + +## Test + +```bash curl -v --cookie "access_token=hello_world" http://localhost:3000 ``` From b4c2609cc6989c868376bc339a215df7a3805bfa Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 6 Jul 2024 02:58:22 -0400 Subject: [PATCH 02/13] Only run workflow during changes to markdown files --- .github/workflows/markdown.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index 544bd7c871..5f83274751 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -1,10 +1,15 @@ name: markdownlint + on: push: branches: - master - main + paths: + - "**.md" pull_request: + paths: + - "**.md" jobs: markdownlint: From 73db67c02cd3e910efa86045871de441881aacfa Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 6 Jul 2024 03:04:14 -0400 Subject: [PATCH 03/13] Fix more inconsistencies --- Makefile | 2 +- docs/middleware/basicauth.md | 4 +-- docs/middleware/compress.md | 4 +-- docs/middleware/cors.md | 4 +-- docs/middleware/encryptcookie.md | 4 +-- docs/middleware/etag.md | 4 +-- docs/middleware/expvar.md | 4 +-- docs/middleware/favicon.md | 4 +-- docs/middleware/helmet.md | 20 +++++++-------- docs/middleware/keyauth.md | 2 +- docs/middleware/pprof.md | 4 +-- docs/middleware/recover.md | 4 +-- docs/middleware/redirect.md | 44 ++++++++++++++++---------------- docs/middleware/requestid.md | 4 +-- docs/middleware/rewrite.md | 8 +++--- docs/middleware/session.md | 4 +-- docs/middleware/skip.md | 4 +-- 17 files changed, 62 insertions(+), 62 deletions(-) diff --git a/Makefile b/Makefile index 0b0008d278..d4fb8f4eee 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ format: ## format: 🎨 Find markdown format issues (Requires markdownlint-cli) .PHONY: markdown format: - markdownlint-cli2 "**/*.md" "#.github" + markdownlint-cli2 "**/*.md" ## lint: 🚨 Run lint checks .PHONY: lint diff --git a/docs/middleware/basicauth.md b/docs/middleware/basicauth.md index 246945ce7b..080f128384 100644 --- a/docs/middleware/basicauth.md +++ b/docs/middleware/basicauth.md @@ -20,8 +20,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/basicauth" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/basicauth" ) ``` diff --git a/docs/middleware/compress.md b/docs/middleware/compress.md index 5a119ce201..51d234cb06 100644 --- a/docs/middleware/compress.md +++ b/docs/middleware/compress.md @@ -22,8 +22,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/compress" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/compress" ) ``` diff --git a/docs/middleware/cors.md b/docs/middleware/cors.md index 3dfe04e3f7..dbe5231578 100644 --- a/docs/middleware/cors.md +++ b/docs/middleware/cors.md @@ -26,8 +26,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/cors" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/cors" ) ``` diff --git a/docs/middleware/encryptcookie.md b/docs/middleware/encryptcookie.md index 4fd565800a..004b4bee17 100644 --- a/docs/middleware/encryptcookie.md +++ b/docs/middleware/encryptcookie.md @@ -28,8 +28,8 @@ To use the Encrypt Cookie middleware, first, import the middleware package as pa ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/encryptcookie" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/encryptcookie" ) ``` diff --git a/docs/middleware/etag.md b/docs/middleware/etag.md index 28cf69195e..6c60df8b4e 100644 --- a/docs/middleware/etag.md +++ b/docs/middleware/etag.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/etag" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/etag" ) ``` diff --git a/docs/middleware/expvar.md b/docs/middleware/expvar.md index 98c74abb51..890ee2353f 100644 --- a/docs/middleware/expvar.md +++ b/docs/middleware/expvar.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - expvarmw "github.com/gofiber/fiber/v3/middleware/expvar" + "github.com/gofiber/fiber/v3" + expvarmw "github.com/gofiber/fiber/v3/middleware/expvar" ) ``` diff --git a/docs/middleware/favicon.md b/docs/middleware/favicon.md index 7b1b66ca5b..7a4b22668d 100644 --- a/docs/middleware/favicon.md +++ b/docs/middleware/favicon.md @@ -22,8 +22,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/favicon" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/favicon" ) ``` diff --git a/docs/middleware/helmet.md b/docs/middleware/helmet.md index 37838bbf10..bc101350b8 100644 --- a/docs/middleware/helmet.md +++ b/docs/middleware/helmet.md @@ -18,26 +18,26 @@ func New(config ...Config) fiber.Handler package main import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/helmet" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/helmet" ) func main() { - app := fiber.New() + app := fiber.New() - app.Use(helmet.New()) + app.Use(helmet.New()) - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Welcome!") - }) + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Welcome!") + }) - app.Listen(":3000") + app.Listen(":3000") } ``` -**Test:** +## Test -```curl +```bash curl -I http://localhost:3000 ``` diff --git a/docs/middleware/keyauth.md b/docs/middleware/keyauth.md index c373ee5080..ce39b820f6 100644 --- a/docs/middleware/keyauth.md +++ b/docs/middleware/keyauth.md @@ -56,7 +56,7 @@ func main() { } ``` -**Test:** +## Test ```bash # No api-key specified -> 400 missing diff --git a/docs/middleware/pprof.md b/docs/middleware/pprof.md index bbac32fd1f..146b639176 100644 --- a/docs/middleware/pprof.md +++ b/docs/middleware/pprof.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/pprof" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/pprof" ) ``` diff --git a/docs/middleware/recover.md b/docs/middleware/recover.md index 8d0a601eac..e8b4870a65 100644 --- a/docs/middleware/recover.md +++ b/docs/middleware/recover.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/recover" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/recover" ) ``` diff --git a/docs/middleware/redirect.md b/docs/middleware/redirect.md index 1c405499f1..0b2551aa00 100644 --- a/docs/middleware/redirect.md +++ b/docs/middleware/redirect.md @@ -18,35 +18,35 @@ func New(config ...Config) fiber.Handler package main import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/redirect" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/redirect" ) func main() { - app := fiber.New() - - app.Use(redirect.New(redirect.Config{ - Rules: map[string]string{ - "/old": "/new", - "/old/*": "/new/$1", - }, - StatusCode: 301, - })) - - app.Get("/new", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") - }) - app.Get("/new/*", func(c fiber.Ctx) error { - return c.SendString("Wildcard: " + c.Params("*")) - }) - - app.Listen(":3000") + app := fiber.New() + + app.Use(redirect.New(redirect.Config{ + Rules: map[string]string{ + "/old": "/new", + "/old/*": "/new/$1", + }, + StatusCode: 301, + })) + + app.Get("/new", func(c fiber.Ctx) error { + return c.SendString("Hello, World!") + }) + app.Get("/new/*", func(c fiber.Ctx) error { + return c.SendString("Wildcard: " + c.Params("*")) + }) + + app.Listen(":3000") } ``` -**Test:** +## Test -```curl +```bash curl http://localhost:3000/old curl http://localhost:3000/old/hello ``` diff --git a/docs/middleware/requestid.md b/docs/middleware/requestid.md index 8af06056b1..739a4a6190 100644 --- a/docs/middleware/requestid.md +++ b/docs/middleware/requestid.md @@ -19,8 +19,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/requestid" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/requestid" ) ``` diff --git a/docs/middleware/rewrite.md b/docs/middleware/rewrite.md index cb364bbad9..110453652b 100644 --- a/docs/middleware/rewrite.md +++ b/docs/middleware/rewrite.md @@ -25,8 +25,8 @@ func New(config ...Config) fiber.Handler package main import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/rewrite" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/rewrite" ) func main() { @@ -51,9 +51,9 @@ func main() { ``` -**Test:** +## Test -```curl +```bash curl http://localhost:3000/old curl http://localhost:3000/old/hello ``` diff --git a/docs/middleware/session.md b/docs/middleware/session.md index 0763b9dfb9..c49bf8c44a 100644 --- a/docs/middleware/session.md +++ b/docs/middleware/session.md @@ -42,8 +42,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/session" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/session" ) ``` diff --git a/docs/middleware/skip.md b/docs/middleware/skip.md index a80bf8513b..5d702dc83c 100644 --- a/docs/middleware/skip.md +++ b/docs/middleware/skip.md @@ -18,8 +18,8 @@ Import the middleware package that is part of the Fiber web framework ```go import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/v3/middleware/skip" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/skip" ) ``` From 2270ee3c4c2eb724328864753f4ba2d634b51205 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 6 Jul 2024 03:09:58 -0400 Subject: [PATCH 04/13] Fixes to markdown under .github/ --- .github/CODE_OF_CONDUCT.md | 4 +-- .github/CONTRIBUTING.md | 4 ++- .github/README.md | 56 ++++++++++++++++---------------- .github/SECURITY.md | 6 +++- .github/pull_request_template.md | 2 +- .github/workflows/markdown.yml | 1 - 6 files changed, 39 insertions(+), 34 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index c8d7ee4458..1b56152c7c 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -71,11 +71,11 @@ Community leaders will follow these Community Impact Guidelines in determining t ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, -available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +available at . Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. +. Translations are available at . diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e35ce19942..1ebcef7b1f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -5,9 +5,11 @@ Before making any changes to this repository, we kindly request you to initiate Please note: we have a [code of conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md), please follow it in all your interactions with the `Fiber` project. ## Pull Requests or Commits + Titles always we must use prefix according to below: > 🔥 Feature, ♻️ Refactor, 🩹 Fix, 🚨 Test, 📚 Doc, 🎨 Style + - 🔥 Feature: Add flow to add person - ♻️ Refactor: Rename file X to Y - 🩹 Fix: Improve flow @@ -17,7 +19,7 @@ Titles always we must use prefix according to below: All pull requests that contain a feature or fix are mandatory to have unit tests. Your PR is only to be merged if you respect this flow. -# 👍 Contribute +## 👍 Contribute If you want to say **thank you** and/or support the active development of `Fiber`: diff --git a/.github/README.md b/.github/README.md index a7cc2f756f..3396838761 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,4 +1,4 @@ -

+

@@ -12,7 +12,7 @@ - + Codecov @@ -24,7 +24,7 @@ -

+

Fiber is an Express inspired web framework built on top of Fasthttp, the fastest HTTP engine for Go. Designed to ease things up for fast development with zero memory allocation and performance in mind.

@@ -57,7 +57,7 @@ This command fetches the Fiber package and adds it to your project's dependencie ## ⚡️ Quickstart -Getting started with Fiber is easy. Here's a basic example to create a simple web server that responds with "Hello, World 👋!" on the root path. This example demonstrates initializing a new Fiber app, setting up a route, and starting the server. +Getting started with Fiber is easy. Here's a basic example to create a simple web server that responds with "Hello, World 👋!" on the root path. This example demonstrates initializing a new Fiber app, setting up a route, and starting the server. ```go package main @@ -100,19 +100,19 @@ These tests are performed by [TechEmpower](https://www.techempower.com/benchmark ## 🎯 Features -- Robust [Routing](https://docs.gofiber.io/guide/routing) -- Serve [Static Files](https://docs.gofiber.io/api/app#static) -- Extreme [Performance](https://docs.gofiber.io/extra/benchmarks) -- [Low Memory](https://docs.gofiber.io/extra/benchmarks) footprint -- [API Endpoints](https://docs.gofiber.io/api/ctx) -- [Middleware](https://docs.gofiber.io/category/-middleware) & [Next](https://docs.gofiber.io/api/ctx#next) support -- [Rapid](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) server-side programming -- [Template Engines](https://github.com/gofiber/template) -- [WebSocket Support](https://github.com/gofiber/contrib/tree/main/websocket) -- [Socket.io Support](https://github.com/gofiber/contrib/tree/main/socketio) -- [Server-Sent Events](https://github.com/gofiber/recipes/tree/master/sse) -- [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- And much more, [explore Fiber](https://docs.gofiber.io/) +- Robust [Routing](https://docs.gofiber.io/guide/routing) +- Serve [Static Files](https://docs.gofiber.io/api/app#static) +- Extreme [Performance](https://docs.gofiber.io/extra/benchmarks) +- [Low Memory](https://docs.gofiber.io/extra/benchmarks) footprint +- [API Endpoints](https://docs.gofiber.io/api/ctx) +- [Middleware](https://docs.gofiber.io/category/-middleware) & [Next](https://docs.gofiber.io/api/ctx#next) support +- [Rapid](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) server-side programming +- [Template Engines](https://github.com/gofiber/template) +- [WebSocket Support](https://github.com/gofiber/contrib/tree/main/websocket) +- [Socket.io Support](https://github.com/gofiber/contrib/tree/main/socketio) +- [Server-Sent Events](https://github.com/gofiber/recipes/tree/master/sse) +- [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) +- And much more, [explore Fiber](https://docs.gofiber.io/) ## 💡 Philosophy @@ -124,14 +124,14 @@ We **listen** to our users in [issues](https://github.com/gofiber/fiber/issues), ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber v3 has been tested with Go versions 1.21 and 1.22. -- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber v3 has been tested with Go versions 1.21 and 1.22. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Examples Listed below are some of the common examples. If you want to see more code examples, please visit our [Recipes repository](https://github.com/gofiber/recipes) or visit our hosted [API documentation](https://docs.gofiber.io). -#### 📖 [**Basic Routing**](https://docs.gofiber.io/#basic-routing) +### 📖 [**Basic Routing**](https://docs.gofiber.io/#basic-routing) ```go func main() { @@ -634,14 +634,14 @@ If you want to say **Thank You** and/or support the active development of `Fiber To ensure your contributions are ready for a Pull Request, please use the following `Makefile` commands. These tools help maintain code quality, consistency. -* **make help**: Display available commands. -* **make audit**: Conduct quality checks. -* **make benchmark**: Benchmark code performance. -* **make coverage**: Generate test coverage report. -* **make format**: Automatically format code. -* **make lint**: Run lint checks. -* **make test**: Execute all tests. -* **make tidy**: Tidy dependencies. +- **make help**: Display available commands. +- **make audit**: Conduct quality checks. +- **make benchmark**: Benchmark code performance. +- **make coverage**: Generate test coverage report. +- **make format**: Automatically format code. +- **make lint**: Run lint checks. +- **make test**: Execute all tests. +- **make tidy**: Tidy dependencies. Run these commands to ensure your code adheres to project standards and best practices. diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 9d4826fe02..a570992536 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -6,6 +6,7 @@ 4. [Incident Response Process](#process) + ## Supported Versions The table below shows the supported versions for Fiber which include security updates. @@ -16,6 +17,7 @@ The table below shows the supported versions for Fiber which include security up | < 1.12.6 | :x: | + ## Reporting security problems to Fiber **DO NOT CREATE AN ISSUE** to report a security problem. Instead, please @@ -24,6 +26,7 @@ send us an e-mail at `team@gofiber.io` or join our discord server via to Fenny or any of the maintainers. + ## Security Point of Contact The security point of contact is [Fenny](https://github.com/Fenny). Fenny responds @@ -35,6 +38,7 @@ of contact are any of the [@maintainers](https://github.com/orgs/gofiber/teams/m The maintainers are the only other persons with administrative access to Fiber's source code. + ## Incident Response Process In case an incident is discovered or reported, we will follow the following @@ -73,4 +77,4 @@ for all of it's members. We learn about critical software updates and security threats from these sources 1. GitHub Security Alerts -2. GitHub: https://status.github.com/ & [@githubstatus](https://twitter.com/githubstatus) +2. GitHub: & [@githubstatus](https://twitter.com/githubstatus) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 073b96030d..c138299087 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,4 +1,4 @@ -## Description +# Description Please provide a clear and concise description of the changes you've made and the problem they address. Include the purpose of the change, any relevant issues it solves, and the benefits it brings to the project. If this change introduces new features or adjustments, highlight them here. diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index 5f83274751..f03a642a24 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -21,4 +21,3 @@ jobs: with: globs: | **/*.md - !.github From c92a9af077ff371f337e8b2228c6ad47fb7681b1 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 6 Jul 2024 03:20:48 -0400 Subject: [PATCH 05/13] More fixes --- docs/guide/faster-fiber.md | 4 +-- docs/guide/grouping.md | 38 ++++++++++----------- docs/guide/routing.md | 4 +-- docs/guide/utils.md | 58 ++++++++++++++++---------------- docs/guide/validation.md | 20 +++++------ docs/middleware/compress.md | 8 ++--- docs/middleware/cors.md | 28 +++++++-------- docs/middleware/rewrite.md | 34 +++++++++---------- docs/middleware/session.md | 1 + docs/middleware/static.md | 4 +-- docs/partials/routing/handler.md | 6 ++-- 11 files changed, 102 insertions(+), 103 deletions(-) diff --git a/docs/guide/faster-fiber.md b/docs/guide/faster-fiber.md index e1cf77a01f..90d2a3581e 100644 --- a/docs/guide/faster-fiber.md +++ b/docs/guide/faster-fiber.md @@ -6,14 +6,12 @@ sidebar_position: 7 ## Custom JSON Encoder/Decoder -Since Fiber v2.32.0, we use **encoding/json** as default json library due to stability and producibility. However, the standard library is a bit slow compared to 3rd party libraries. If you're not happy with the performance of **encoding/json**, we recommend you to use these libraries: +Since Fiber v2.32.0, we have adopted `encoding/json` as the default JSON library for its stability and reliability. However, the standard library can be slower than some third-party alternatives. If you find the performance of `encoding/json` unsatisfactory, we suggest considering these libraries: - [goccy/go-json](https://github.com/goccy/go-json) - [bytedance/sonic](https://github.com/bytedance/sonic) - [segmentio/encoding](https://github.com/segmentio/encoding) -- [mailru/easyjson](https://github.com/mailru/easyjson) - [minio/simdjson-go](https://github.com/minio/simdjson-go) -- [wI2L/jettison](https://github.com/wI2L/jettison) ```go title="Example" package main diff --git a/docs/guide/grouping.md b/docs/guide/grouping.md index 4ed4622c18..6374f102f2 100644 --- a/docs/guide/grouping.md +++ b/docs/guide/grouping.md @@ -10,23 +10,23 @@ In general, the Group functionality in Fiber behaves similarly to ExpressJS. Gro ## Paths -Like **Routing**, groups can also have paths that belong to a cluster. +Like `Routing`, groups can also have paths that belong to a cluster. ```go func main() { - app := fiber.New() + app := fiber.New() - api := app.Group("/api", middleware) // /api + api := app.Group("/api", middleware) // /api - v1 := api.Group("/v1", middleware) // /api/v1 - v1.Get("/list", handler) // /api/v1/list - v1.Get("/user", handler) // /api/v1/user + v1 := api.Group("/v1", middleware) // /api/v1 + v1.Get("/list", handler) // /api/v1/list + v1.Get("/user", handler) // /api/v1/user - v2 := api.Group("/v2", middleware) // /api/v2 - v2.Get("/list", handler) // /api/v2/list - v2.Get("/user", handler) // /api/v2/user + v2 := api.Group("/v2", middleware) // /api/v2 + v2.Get("/list", handler) // /api/v2/list + v2.Get("/user", handler) // /api/v2/user - log.Fatal(app.Listen(":3000")) + log.Fatal(app.Listen(":3000")) } ``` @@ -34,19 +34,19 @@ A **Group** of paths can have an optional handler. ```go func main() { - app := fiber.New() + app := fiber.New() - api := app.Group("/api") // /api + api := app.Group("/api") // /api - v1 := api.Group("/v1") // /api/v1 - v1.Get("/list", handler) // /api/v1/list - v1.Get("/user", handler) // /api/v1/user + v1 := api.Group("/v1") // /api/v1 + v1.Get("/list", handler) // /api/v1/list + v1.Get("/user", handler) // /api/v1/user - v2 := api.Group("/v2") // /api/v2 - v2.Get("/list", handler) // /api/v2/list - v2.Get("/user", handler) // /api/v2/user + v2 := api.Group("/v2") // /api/v2 + v2.Get("/list", handler) // /api/v2/list + v2.Get("/user", handler) // /api/v2/user - log.Fatal(app.Listen(":3000")) + log.Fatal(app.Listen(":3000")) } ``` diff --git a/docs/guide/routing.md b/docs/guide/routing.md index 3badeac05f..450932ccfb 100644 --- a/docs/guide/routing.md +++ b/docs/guide/routing.md @@ -25,7 +25,7 @@ Route paths, combined with a request method, define the endpoints at which reque ```go // This route path will match requests to the root route, "/": app.Get("/", func(c fiber.Ctx) error { - return c.SendString("root") + return c.SendString("root") }) // This route path will match requests to "/about": @@ -315,7 +315,7 @@ app.Use(func(c fiber.Ctx) error { }) app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") + return c.SendString("Hello, World!") }) ``` diff --git a/docs/guide/utils.md b/docs/guide/utils.md index 9d456237a7..24ed2362ba 100644 --- a/docs/guide/utils.md +++ b/docs/guide/utils.md @@ -19,14 +19,14 @@ func Convert[T any](value string, convertor func(string) (T, error), defaultValu ```go title="Example" // GET http://example.com/id/bb70ab33-d455-4a03-8d78-d3c1dacae9ff app.Get("/id/:id", func(c fiber.Ctx) error { - fiber.Convert(c.Params("id"), uuid.Parse) // UUID(bb70ab33-d455-4a03-8d78-d3c1dacae9ff), nil + fiber.Convert(c.Params("id"), uuid.Parse) // UUID(bb70ab33-d455-4a03-8d78-d3c1dacae9ff), nil // GET http://example.com/search?id=65f6f54221fb90e6a6b76db7 app.Get("/search", func(c fiber.Ctx) error) { - fiber.Convert(c.Query("id"), mongo.ParseObjectID) // objectid(65f6f54221fb90e6a6b76db7), nil - fiber.Convert(c.Query("id"), uuid.Parse) // uuid.Nil, error(cannot parse given uuid) - fiber.Convert(c.Query("id"), uuid.Parse, mongo.NewObjectID) // new object id generated and return nil as error. + fiber.Convert(c.Query("id"), mongo.ParseObjectID) // objectid(65f6f54221fb90e6a6b76db7), nil + fiber.Convert(c.Query("id"), uuid.Parse) // uuid.Nil, error(cannot parse given uuid) + fiber.Convert(c.Query("id"), uuid.Parse, mongo.NewObjectID) // new object id generated and return nil as error. } // ... @@ -44,11 +44,11 @@ func GetReqHeader[V any](c Ctx, key string, defaultValue ...V) V ```go title="Example" app.Get("/search", func(c fiber.Ctx) error { - // curl -X GET http://example.com/search -H "X-Request-ID: 12345" -H "X-Request-Name: John" - GetReqHeader[int](c, "X-Request-ID") // => returns 12345 as integer. - GetReqHeader[string](c, "X-Request-Name") // => returns "John" as string. - GetReqHeader[string](c, "unknownParam", "default") // => returns "default" as string. - // ... + // curl -X GET http://example.com/search -H "X-Request-ID: 12345" -H "X-Request-Name: John" + GetReqHeader[int](c, "X-Request-ID") // => returns 12345 as integer. + GetReqHeader[string](c, "X-Request-Name") // => returns "John" as string. + GetReqHeader[string](c, "unknownParam", "default") // => returns "default" as string. + // ... }) ``` @@ -68,20 +68,20 @@ func Locals[V any](c Ctx, key any, value ...V) V ```go title="Example" app.Use("/user/:user/:id", func(c fiber.Ctx) error { - // set local values - fiber.Locals[string](c, "user", "john") - fiber.Locals[int](c, "id", 25) - // ... - - return c.Next() + // set local values + fiber.Locals[string](c, "user", "john") + fiber.Locals[int](c, "id", 25) + // ... + + return c.Next() }) app.Get("/user/*", func(c fiber.Ctx) error { - // get local values - name := fiber.Locals[string](c, "user") // john - age := fiber.Locals[int](c, "id") // 25 - // ... + // get local values + name := fiber.Locals[string](c, "user") // john + age := fiber.Locals[int](c, "id") // 25 + // ... }) ``` @@ -96,11 +96,11 @@ func Params[V any](c Ctx, key string, defaultValue ...V) V ```go title="Example" app.Get("/user/:user/:id", func(c fiber.Ctx) error { - // http://example.com/user/john/25 - Params[int](c, "id") // => returns 25 as integer. - Params[int](c, "unknownParam", 99) // => returns the default 99 as integer. - // ... - return c.SendString("Hello, " + fiber.Params[string](c, "user")) + // http://example.com/user/john/25 + Params[int](c, "id") // => returns 25 as integer. + Params[int](c, "unknownParam", 99) // => returns the default 99 as integer. + // ... + return c.SendString("Hello, " + fiber.Params[string](c, "user")) }) ``` @@ -115,10 +115,10 @@ func Query[V any](c Ctx, key string, defaultValue ...V) V ```go title="Example" app.Get("/search", func(c fiber.Ctx) error { - // http://example.com/search?name=john&age=25 - Query[string](c, "name") // => returns "john" - Query[int](c, "age") // => returns 25 as integer. - Query[string](c, "unknownParam", "default") // => returns "default" as string. - // ... + // http://example.com/search?name=john&age=25 + Query[string](c, "name") // => returns "john" + Query[int](c, "age") // => returns 25 as integer. + Query[string](c, "unknownParam", "default") // => returns "default" as string. + // ... }) ``` diff --git a/docs/guide/validation.md b/docs/guide/validation.md index 450255264d..7226347fd9 100644 --- a/docs/guide/validation.md +++ b/docs/guide/validation.md @@ -27,18 +27,18 @@ app := fiber.New(fiber.Config{ }) type User struct { - Name string `json:"name" form:"name" query:"name" validate:"required"` - Age int `json:"age" form:"age" query:"age" validate:"gte=0,lte=100"` + Name string `json:"name" form:"name" query:"name" validate:"required"` + Age int `json:"age" form:"age" query:"age" validate:"gte=0,lte=100"` } app.Post("/", func(c fiber.Ctx) error { - user := new(User) - - // Works with all bind methods - Body, Query, Form, ... - if err := c.Bind().Body(user); err != nil { // <- here you receive the validation errors - return err - } - - return c.JSON(user) + user := new(User) + + // Works with all bind methods - Body, Query, Form, ... + if err := c.Bind().Body(user); err != nil { // <- here you receive the validation errors + return err + } + + return c.JSON(user) }) ``` diff --git a/docs/middleware/compress.md b/docs/middleware/compress.md index 51d234cb06..aac21681d6 100644 --- a/docs/middleware/compress.md +++ b/docs/middleware/compress.md @@ -40,10 +40,10 @@ app.Use(compress.New(compress.Config{ // Skip middleware for specific routes app.Use(compress.New(compress.Config{ - Next: func(c fiber.Ctx) bool { - return c.Path() == "/dont_compress" - }, - Level: compress.LevelBestSpeed, // 1 + Next: func(c fiber.Ctx) bool { + return c.Path() == "/dont_compress" + }, + Level: compress.LevelBestSpeed, // 1 })) ``` diff --git a/docs/middleware/cors.md b/docs/middleware/cors.md index dbe5231578..1027929654 100644 --- a/docs/middleware/cors.md +++ b/docs/middleware/cors.md @@ -69,25 +69,25 @@ If you need to allow wildcard origins, use `AllowOrigins` with a wildcard `"*"` ```go // dbCheckOrigin checks if the origin is in the list of allowed origins in the database. func dbCheckOrigin(db *sql.DB, origin string) bool { - // Placeholder query - adjust according to your database schema and query needs - query := "SELECT COUNT(*) FROM allowed_origins WHERE origin = $1" - - var count int - err := db.QueryRow(query, origin).Scan(&count) - if err != nil { - // Handle error (e.g., log it); for simplicity, we return false here - return false - } - - return count > 0 + // Placeholder query - adjust according to your database schema and query needs + query := "SELECT COUNT(*) FROM allowed_origins WHERE origin = $1" + + var count int + err := db.QueryRow(query, origin).Scan(&count) + if err != nil { + // Handle error (e.g., log it); for simplicity, we return false here + return false + } + + return count > 0 } // ... app.Use(cors.New(cors.Config{ - AllowOriginsFunc: func(origin string) bool { - return dbCheckOrigin(db, origin) - }, + AllowOriginsFunc: func(origin string) bool { + return dbCheckOrigin(db, origin) + }, })) ``` diff --git a/docs/middleware/rewrite.md b/docs/middleware/rewrite.md index 110453652b..99c2acf882 100644 --- a/docs/middleware/rewrite.md +++ b/docs/middleware/rewrite.md @@ -30,23 +30,23 @@ import ( ) func main() { - app := fiber.New() - - app.Use(rewrite.New(rewrite.Config{ - Rules: map[string]string{ - "/old": "/new", - "/old/*": "/new/$1", - }, - })) - - app.Get("/new", func(c fiber.Ctx) error { - return c.SendString("Hello, World!") - }) - app.Get("/new/*", func(c fiber.Ctx) error { - return c.SendString("Wildcard: " + c.Params("*")) - }) - - app.Listen(":3000") + app := fiber.New() + + app.Use(rewrite.New(rewrite.Config{ + Rules: map[string]string{ + "/old": "/new", + "/old/*": "/new/$1", + }, + })) + + app.Get("/new", func(c fiber.Ctx) error { + return c.SendString("Hello, World!") + }) + app.Get("/new/*", func(c fiber.Ctx) error { + return c.SendString("Wildcard: " + c.Params("*")) + }) + + app.Listen(":3000") } ``` diff --git a/docs/middleware/session.md b/docs/middleware/session.md index c49bf8c44a..39b9ccc801 100644 --- a/docs/middleware/session.md +++ b/docs/middleware/session.md @@ -134,6 +134,7 @@ You can use any storage from our [storage](https://github.com/gofiber/storage/) ```go storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3 + store := session.New(session.Config{ Storage: storage, }) diff --git a/docs/middleware/static.md b/docs/middleware/static.md index 0a1d8a88aa..a8c7ec6093 100644 --- a/docs/middleware/static.md +++ b/docs/middleware/static.md @@ -167,7 +167,7 @@ You can set `CacheDuration` config property to `-1` to disable caching. ```go var ConfigDefault = Config{ - Index: []string{"index.html"}, - CacheDuration: 10 * time.Second, + Index: []string{"index.html"}, + CacheDuration: 10 * time.Second, } ``` diff --git a/docs/partials/routing/handler.md b/docs/partials/routing/handler.md index 5cff828d4c..2b94a07cda 100644 --- a/docs/partials/routing/handler.md +++ b/docs/partials/routing/handler.md @@ -30,12 +30,12 @@ func (app *App) All(path string, handler Handler, middlewares ...Handler) Router ```go title="Examples" // Simple GET handler app.Get("/api/list", func(c fiber.Ctx) error { - return c.SendString("I'm a GET request!") + return c.SendString("I'm a GET request!") }) // Simple POST handler app.Post("/api/register", func(c fiber.Ctx) error { - return c.SendString("I'm a POST request!") + return c.SendString("I'm a POST request!") }) ``` @@ -71,7 +71,7 @@ app.Use([]string{"/api", "/home"}, func(c fiber.Ctx) error { // Attach multiple handlers app.Use("/api", func(c fiber.Ctx) error { - c.Set("X-Custom-Header", random.String(32)) + c.Set("X-Custom-Header", random.String(32)) return c.Next() }, func(c fiber.Ctx) error { return c.Next() From 7d30a4e0e7da26611d90968e91267c0189c57d58 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sat, 6 Jul 2024 03:38:00 -0400 Subject: [PATCH 06/13] Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- addon/retry/README.md | 4 ++-- binder/README.md | 9 ++++----- docs/api/bind.md | 2 +- docs/api/fiber.md | 2 +- docs/api/hooks.md | 4 ++-- docs/middleware/limiter.md | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/addon/retry/README.md b/addon/retry/README.md index 0ea963b985..a3af44070b 100644 --- a/addon/retry/README.md +++ b/addon/retry/README.md @@ -1,8 +1,8 @@ # Retry Addon Retry addon for [Fiber](https://github.com/gofiber/fiber) designed to apply retry mechanism for unsuccessful network -operations. This addon uses exponential backoff algorithm with jitter. It calls the function multiple times and tries -to make it successful. If all calls are failed, then, it returns error. It adds a jitter at each retry step because adding +operations. This addon uses an exponential backoff algorithm with jitter. It calls the function multiple times and tries +to make it successful. If all calls are failed, then, it returns an error. It adds a jitter at each retry step because adding a jitter is a way to break synchronization across the client and avoid collision. ## Table of Contents diff --git a/binder/README.md b/binder/README.md index b1b846b736..b619add677 100644 --- a/binder/README.md +++ b/binder/README.md @@ -1,6 +1,6 @@ # Fiber Binders -Binder is new request/response binding feature for Fiber. By aganist 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. 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: - BodyParser - ParamsParser @@ -25,7 +25,7 @@ Binder is new request/response binding feature for Fiber. By aganist old Fiber p ### Binding into the Struct -Fiber supports binding into the struct with [gorilla/schema](https://github.com/gorilla/schema). Here's an example for it: +Fiber supports binding into the struct with [gorilla/schema](https://github.com/gorilla/schema). Here's an example: ```go // Field names should start with an uppercase letter @@ -62,8 +62,7 @@ app.Post("/", func(c fiber.Ctx) error { ### Binding into the Map -Fiber supports binding into the `map[string]string` or `map[string][]string`. Here's an example for it: - +Fiber supports binding into the `map[string]string` or `map[string][]string`. Here's an example: ```go app.Get("/", func(c fiber.Ctx) error { p := make(map[string][]string) @@ -115,7 +114,7 @@ app.Get("/", func(c fiber.Ctx) error { ### Defining Custom Binder -We didn't add much binder to make Fiber codebase minimal. But if you want to use your binders, it's easy to register and use them. Here's an example for TOML 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. ```go type Person struct { diff --git a/docs/api/bind.md b/docs/api/bind.md index f01c4b870e..927d423b92 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -192,7 +192,7 @@ app.Post("/", func(c fiber.Ctx) error { Binds the request xml form body to a struct. -It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a XML body with a field called Pass, you would use a struct field of `xml:"pass"`. +It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse an XML body with a field called Pass, you would use a struct field of `xml:"pass"`. ```go title="Signature" func (b *Bind) XML(out any) error diff --git a/docs/api/fiber.md b/docs/api/fiber.md index 8e243ecd76..16f23b9e61 100644 --- a/docs/api/fiber.md +++ b/docs/api/fiber.md @@ -111,7 +111,7 @@ app.Listen(":8080", fiber.ListenConfig{ | ListenerAddrFunc | `func(addr net.Addr)` | Allows accessing and customizing `net.Listener`. | `nil` | | ListenerNetwork | `string` | Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only). WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chosen. | `tcp4` | | OnShutdownError | `func(err error)` | Allows to customize error behavior when gracefully shutting down the server by given signal. Prints error with `log.Fatalf()` | `nil` | -| OnShutdownSuccess | `func()` | Allows to customize success behavior when gracefully shutting down the server by given signal. | `nil` | +| OnShutdownSuccess | `func()` | Allows customizing success behavior when gracefully shutting down the server by given signal. | `nil` | | TLSConfigFunc | `func(tlsConfig *tls.Config)` | Allows customizing `tls.Config` as you want. | `nil` | ### Listen diff --git a/docs/api/hooks.md b/docs/api/hooks.md index e9102a35d1..2ef3a4619a 100644 --- a/docs/api/hooks.md +++ b/docs/api/hooks.md @@ -7,7 +7,7 @@ sidebar_position: 7 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -With Fiber v2.30.0, you can execute custom user functions when to run some methods. Here is a list of this hooks: +With Fiber v2.30.0, you can execute custom user functions when to run some methods. Here is a list of these hooks: - [OnRoute](#onroute) - [OnName](#onname) @@ -217,4 +217,4 @@ func main() { :::caution -OnName/OnRoute/OnGroup/OnGroupName hooks are mount-sensitive. If you use one of these routes on sub app and you mount it; paths of routes and groups will start with mount prefix. +OnName/OnRoute/OnGroup/OnGroupName hooks are mount-sensitive. If you use one of these routes on sub app, and you mount it; paths of routes and groups will start with mount prefix. diff --git a/docs/middleware/limiter.md b/docs/middleware/limiter.md index 80574a8be8..76f334bde8 100644 --- a/docs/middleware/limiter.md +++ b/docs/middleware/limiter.md @@ -68,7 +68,7 @@ app.Use(limiter.New(limiter.Config{ })) ``` -This means that every window will take into account the previous window(if there was any). The given formula for the rate is: +This means that every window will consider the previous window (if there was any). The given formula for the rate is: ```text weightOfPreviousWindpw = previous window's amount request * (whenNewWindow / Expiration) From 347e051592def63a8d078e5b447bcf9c7cc26daa Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sat, 6 Jul 2024 03:39:52 -0400 Subject: [PATCH 07/13] Fix typo in limiter docs --- docs/middleware/limiter.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/middleware/limiter.md b/docs/middleware/limiter.md index 76f334bde8..edccec20d2 100644 --- a/docs/middleware/limiter.md +++ b/docs/middleware/limiter.md @@ -71,8 +71,8 @@ app.Use(limiter.New(limiter.Config{ This means that every window will consider the previous window (if there was any). The given formula for the rate is: ```text -weightOfPreviousWindpw = previous window's amount request * (whenNewWindow / Expiration) -rate = weightOfPreviousWindpw + current window's amount request. +weightOfPreviousWindow = previous window's amount request * (whenNewWindow / Expiration) +rate = weightOfPreviousWindow + current window's amount request. ``` ## Config From f8e5cc56e717cf3336b8ee4402cd6f0589e3463a Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sat, 6 Jul 2024 03:40:52 -0400 Subject: [PATCH 08/13] Add missing space before code-block --- binder/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/binder/README.md b/binder/README.md index b619add677..676e1c9e89 100644 --- a/binder/README.md +++ b/binder/README.md @@ -63,6 +63,7 @@ app.Post("/", func(c fiber.Ctx) error { ### Binding into the Map Fiber supports binding into the `map[string]string` or `map[string][]string`. Here's an example: + ```go app.Get("/", func(c fiber.Ctx) error { p := make(map[string][]string) From 5e17ab0c4873dbb579a358dba7056b900affcfb0 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sat, 6 Jul 2024 22:54:23 -0400 Subject: [PATCH 09/13] Add check for dead-links --- .github/workflows/markdown.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index f03a642a24..7bbecff21d 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -15,9 +15,14 @@ jobs: markdownlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Fetch Repository + uses: actions/checkout@v4 - - uses: DavidAnson/markdownlint-cli2-action@v16 + - name: Run markdownlint-cli2 + uses: DavidAnson/markdownlint-cli2-action@v16 with: globs: | **/*.md + + - name: Markdown link check + uses: gaurav-nelson/github-action-markdown-link-check@v1 From 6cbdcb8ca7bbd34def21f0d07abe42a277c20707 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:20:09 -0400 Subject: [PATCH 10/13] Add write-good --- .github/workflows/markdown.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index 7bbecff21d..aaf8ecb74c 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -24,5 +24,17 @@ jobs: globs: | **/*.md - - name: Markdown link check - uses: gaurav-nelson/github-action-markdown-link-check@v1 + - name: Run write-good + id: write-good + uses: tomwhross/write-good-action@v1.6 + + - run: echo "${{ steps.write-good.outputs.result }}" + + - name: Post suggestions to Pull Request + uses: mshick/add-pr-comment@v2 + if: ${{ steps.write-good.outputs.result }} + with: + message: | + ${{ steps.write-good.outputs.result }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + allow-repeats: false From 896bfa632dbc589e5efa7a0cf85ff7cf11ef4d85 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:37:19 -0400 Subject: [PATCH 11/13] Remove legacy README files --- .github/workflows/markdown.yml | 19 +---- docs/intro.md | 5 -- docs/whats_new.md | 2 +- middleware/adaptor/README.md | 139 --------------------------------- middleware/helmet/README.md | 37 --------- middleware/keyauth/README.md | 41 ---------- 6 files changed, 3 insertions(+), 240 deletions(-) delete mode 100644 middleware/adaptor/README.md delete mode 100644 middleware/helmet/README.md delete mode 100644 middleware/keyauth/README.md diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index aaf8ecb74c..513b75ab9f 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -6,10 +6,10 @@ on: - master - main paths: - - "**.md" + - "**/*.md" pull_request: paths: - - "**.md" + - "**/*.md" jobs: markdownlint: @@ -23,18 +23,3 @@ jobs: with: globs: | **/*.md - - - name: Run write-good - id: write-good - uses: tomwhross/write-good-action@v1.6 - - - run: echo "${{ steps.write-good.outputs.result }}" - - - name: Post suggestions to Pull Request - uses: mshick/add-pr-comment@v2 - if: ${{ steps.write-good.outputs.result }} - with: - message: | - ${{ steps.write-good.outputs.result }} - repo-token: ${{ secrets.GITHUB_TOKEN }} - allow-repeats: false diff --git a/docs/intro.md b/docs/intro.md index 2fd92a37fd..10e94b3dd6 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -183,8 +183,3 @@ http://localhost:3000/hello.html http://localhost:3000/js/jquery.js http://localhost:3000/css/style.css ``` - -### Note - -For more information on how to build APIs in Go with Fiber, please check out this excellent article -[on building an express-style API in Go with Fiber](https://blog.logrocket.com/express-style-api-go-fiber/). diff --git a/docs/whats_new.md b/docs/whats_new.md index fd01c4a698..9155792f6b 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -7,7 +7,7 @@ toc_max_heading_level: 3 :::caution -Its a draft, not finished yet. +It's a draft, not finished yet. ::: diff --git a/middleware/adaptor/README.md b/middleware/adaptor/README.md deleted file mode 100644 index 8bacab410a..0000000000 --- a/middleware/adaptor/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# Adaptor - -## Install - -```bash -go get -u github.com/gofiber/fiber/v3 -go get -u github.com/gofiber/fiber/middleware/adaptor -``` - -## Functions - -| Name | Signature | Description -| :--- | :--- | :--- -| HTTPHandler | `HTTPHandler(h http.Handler) fiber.Handler` | http.Handler -> fiber.Handler -| HTTPHandlerFunc | `HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler` | http.HandlerFunc -> fiber.Handler -| HTTPMiddleware | `HTTPHandlerFunc(mw func(http.Handler) http.Handler) fiber.Handler` | func(http.Handler) http.Handler -> fiber.Handler -| FiberHandler | `FiberHandler(h fiber.Handler) http.Handler` | fiber.Handler -> http.Handler -| FiberHandlerFunc | `FiberHandlerFunc(h fiber.Handler) http.HandlerFunc` | fiber.Handler -> http.HandlerFunc -| FiberApp | `FiberApp(app *fiber.App) http.HandlerFunc` | Fiber app -> http.HandlerFunc - -## net/http to Fiber - -```go -package main - -import ( - "fmt" - "net/http" - - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" -) - -func main() { - // New fiber app - app := fiber.New() - - // http.Handler -> fiber.Handler - app.Get("/", adaptor.HTTPHandler(handler(greet))) - - // http.HandlerFunc -> fiber.Handler - app.Get("/func", adaptor.HTTPHandlerFunc(greet)) - - // Listen on port 3000 - app.Listen(":3000") -} - -func handler(f http.HandlerFunc) http.Handler { - return http.HandlerFunc(f) -} - -func greet(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "Hello World!") -} -``` - -## net/http middleware to Fiber - -```go -package main - -import ( - "log" - "net/http" - - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" -) - -func main() { - // New fiber app - app := fiber.New() - - // http middleware -> fiber.Handler - app.Use(adaptor.HTTPMiddleware(logMiddleware)) - - // Listen on port 3000 - app.Listen(":3000") -} - -func logMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Println("log middleware") - next.ServeHTTP(w, r) - }) -} -``` - -## Fiber Handler to net/http - -```go -package main - -import ( - "net/http" - - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" -) - -func main() { - // fiber.Handler -> http.Handler - http.Handle("/", adaptor.FiberHandler(greet)) - - // fiber.Handler -> http.HandlerFunc - http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet)) - - // Listen on port 3000 - http.ListenAndServe(":3000", nil) -} - -func greet(c fiber.Ctx) error { - return c.SendString("Hello World!") -} -``` - -## Fiber App to net/http - -```go -package main - -import ( - "github.com/gofiber/adaptor/v2" - "github.com/gofiber/fiber/v3" - "net/http" -) -func main() { - app := fiber.New() - - app.Get("/greet", greet) - - // Listen on port 3000 - http.ListenAndServe(":3000", adaptor.FiberApp(app)) -} - -func greet(c fiber.Ctx) error { - return c.SendString("Hello World!") -} -``` diff --git a/middleware/helmet/README.md b/middleware/helmet/README.md deleted file mode 100644 index e5724deef5..0000000000 --- a/middleware/helmet/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Helmet - -## Install - -```bash -go get -u github.com/gofiber/fiber/v3 -go get -u github.com/gofiber/middleware/helmet -``` - -## Example - -```go -package main - -import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/helmet" -) - -func main() { - app := fiber.New() - - app.Use(helmet.New()) - - app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Welcome!") - }) - - app.Listen(":3000") -} -``` - -## Test - -```bash -curl -I http://localhost:3000 -``` diff --git a/middleware/keyauth/README.md b/middleware/keyauth/README.md deleted file mode 100644 index 734ad40244..0000000000 --- a/middleware/keyauth/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Key Authentication - -## Install - -```bash -go get -u github.com/gofiber/fiber/v3 -go get -u github.com/gofiber/keyauth/v2 -``` - -## Example - -```go -package main - -import ( - "github.com/gofiber/fiber/v3" - "github.com/gofiber/fiber/middleware/keyauth" -) - -func main() { - app := fiber.New() - - app.Use(keyauth.New(keyauth.Config{ - KeyLookup: "cookie:access_token", - ContextKey: "my_token", - })) - - app.Get("/", func(c fiber.Ctx) error { - token := c.TokenFromContext(c) // "" is returned if not found - return c.SendString(token) - }) - - app.Listen(":3000") -} -``` - -## Test - -```bash -curl -v --cookie "access_token=hello_world" http://localhost:3000 -``` From 749bdf75072c2c869219da0522567fd132e80fa4 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sun, 7 Jul 2024 21:43:00 -0400 Subject: [PATCH 12/13] Fix glob for skipping .md files --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/linter.yml | 8 ++++++++ .github/workflows/test.yml | 4 ++-- .github/workflows/vulncheck.yml | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 4a24c2306e..42aff934c7 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -6,12 +6,12 @@ on: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" pull_request: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" name: Benchmark jobs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 82036cc967..0da6ef3777 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -8,12 +8,12 @@ on: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" pull_request: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" schedule: - cron: "0 3 * * 6" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 67a37b4429..12e0e5bbfc 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -6,7 +6,15 @@ on: branches: - master - main + paths: + - "**" + - "!docs/**" + - "!**/*.md" pull_request: + paths: + - "**" + - "!docs/**" + - "!**/*.md" permissions: # Required: allow read access to the content for analysis. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e6706493a9..f857cbe0f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,12 +8,12 @@ on: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" pull_request: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" jobs: unit: diff --git a/.github/workflows/vulncheck.yml b/.github/workflows/vulncheck.yml index e6d29ccb4b..bc68af3378 100644 --- a/.github/workflows/vulncheck.yml +++ b/.github/workflows/vulncheck.yml @@ -8,12 +8,12 @@ on: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" pull_request: paths: - "**" - "!docs/**" - - "!**.md" + - "!**/*.md" jobs: govulncheck-check: From ac83bac6315910dfce68ed08da1ba77d89d3e537 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sun, 7 Jul 2024 21:45:53 -0400 Subject: [PATCH 13/13] Use paths-ignore instead --- .github/workflows/auto-labeler.yml | 1 + .github/workflows/benchmark.yml | 12 ++++-------- .github/workflows/codeql-analysis.yml | 12 ++++-------- .github/workflows/linter.yml | 12 ++++-------- .github/workflows/test.yml | 12 ++++-------- .github/workflows/vulncheck.yml | 12 ++++-------- 6 files changed, 21 insertions(+), 40 deletions(-) diff --git a/.github/workflows/auto-labeler.yml b/.github/workflows/auto-labeler.yml index b0fcc599b2..7b2cdac10b 100644 --- a/.github/workflows/auto-labeler.yml +++ b/.github/workflows/auto-labeler.yml @@ -5,6 +5,7 @@ on: types: [opened, edited, milestoned] pull_request_target: types: [opened] + permissions: contents: read issues: write diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 42aff934c7..e00227d881 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -3,15 +3,11 @@ on: branches: - master - main - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" pull_request: - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" name: Benchmark jobs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0da6ef3777..b145d1cd4c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -5,15 +5,11 @@ on: branches: - master - main - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" pull_request: - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" schedule: - cron: "0 3 * * 6" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 12e0e5bbfc..87ca5a1e1c 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -6,15 +6,11 @@ on: branches: - master - main - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" pull_request: - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" permissions: # Required: allow read access to the content for analysis. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f857cbe0f9..d7dc643b71 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,15 +5,11 @@ on: branches: - master - main - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" pull_request: - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" jobs: unit: diff --git a/.github/workflows/vulncheck.yml b/.github/workflows/vulncheck.yml index bc68af3378..31c252eb03 100644 --- a/.github/workflows/vulncheck.yml +++ b/.github/workflows/vulncheck.yml @@ -5,15 +5,11 @@ on: branches: - master - main - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" pull_request: - paths: - - "**" - - "!docs/**" - - "!**/*.md" + paths-ignore: + - "**/*.md" jobs: govulncheck-check: