From a29edcff9948c2e1bb91ac3b67b0944411ed82bc Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Wed, 13 Nov 2024 00:56:37 -0500 Subject: [PATCH 1/6] Updates to documentation --- .github/README.md | 330 +++++++++++++++++----------- docs/api/app.md | 497 +++++++++++++++++++++++++++---------------- docs/api/bind.md | 343 +++++++++++++++-------------- docs/api/hooks.md | 89 ++++---- docs/api/log.md | 64 +++--- docs/api/redirect.md | 34 ++- 6 files changed, 815 insertions(+), 542 deletions(-) diff --git a/.github/README.md b/.github/README.md index 61159412e8..d3eca5b610 100644 --- a/.github/README.md +++ b/.github/README.md @@ -39,7 +39,7 @@ Fiber v3 is currently in beta and under active development. While it offers exci ## βš™οΈ Installation -Fiber requires **Go version `1.22` or higher** to run. If you need to install or upgrade Go, visit the [official Go download page](https://go.dev/dl/). To start setting up your project. Create a new directory for your project and navigate into it. Then, initialize your project with Go modules by executing the following command in your terminal: +Fiber requires **Go version `1.22` or higher** to run. If you need to install or upgrade Go, visit the [official Go download page](https://go.dev/dl/). To start setting up your project, create a new directory for your project and navigate into it. Then, initialize your project with Go modules by executing the following command in your terminal: ```bash go mod init github.com/your/repo @@ -59,7 +59,7 @@ This command fetches the Fiber package and adds it to your project's dependencie 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 +```go title="Example" package main import ( @@ -133,7 +133,16 @@ Listed below are some of the common examples. If you want to see more code examp ### πŸ“– [**Basic Routing**](https://docs.gofiber.io/#basic-routing) -```go +```go title="Example" +package main + +import ( + "fmt" + "log" + + "github.com/gofiber/fiber/v3" +) + func main() { app := fiber.New() @@ -169,23 +178,33 @@ func main() { log.Fatal(app.Listen(":3000")) } - ``` #### πŸ“– [**Route Naming**](https://docs.gofiber.io/api/app#name) -```go +```go title="Example" +package main + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/gofiber/fiber/v3" +) + func main() { app := fiber.New() - // GET /api/register app.Get("/api/*", func(c fiber.Ctx) error { msg := fmt.Sprintf("βœ‹ %s", c.Params("*")) return c.SendString(msg) // => βœ‹ register }).Name("api") - data, _ := json.MarshalIndent(app.GetRoute("api"), "", " ") - fmt.Print(string(data)) + route := app.GetRoute("api") + + data, _ := json.MarshalIndent(route, "", " ") + fmt.Println(string(data)) // Prints: // { // "method": "GET", @@ -198,15 +217,24 @@ func main() { log.Fatal(app.Listen(":3000")) } - ``` #### πŸ“– [**Serving Static Files**](https://docs.gofiber.io/api/app#static) -```go +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/static" +) + func main() { app := fiber.New() + // Serve static files from the "./public" directory app.Get("/*", static.New("./public")) // => http://localhost:3000/js/script.js // => http://localhost:3000/css/style.css @@ -215,27 +243,36 @@ func main() { // => http://localhost:3000/prefix/js/script.js // => http://localhost:3000/prefix/css/style.css + // Serve a single file for any unmatched routes app.Get("*", static.New("./public/index.html")) - // => http://localhost:3000/any/path/shows/index/html + // => http://localhost:3000/any/path/shows/index.html log.Fatal(app.Listen(":3000")) } - ``` #### πŸ“– [**Middleware & Next**](https://docs.gofiber.io/api/ctx#next) -```go +```go title="Example" +package main + +import ( + "fmt" + "log" + + "github.com/gofiber/fiber/v3" +) + func main() { app := fiber.New() - // Match any route + // Middleware that matches any route app.Use(func(c fiber.Ctx) error { fmt.Println("πŸ₯‡ First handler") return c.Next() }) - // Match all routes starting with /api + // Middleware that matches all routes starting with /api app.Use("/api", func(c fiber.Ctx) error { fmt.Println("πŸ₯ˆ Second handler") return c.Next() @@ -249,13 +286,12 @@ func main() { log.Fatal(app.Listen(":3000")) } - ```
πŸ“š Show more code examples -### Views engines +### Views Engines πŸ“– [Config](https://docs.gofiber.io/api/fiber#config) πŸ“– [Engines](https://github.com/gofiber/template) @@ -263,11 +299,9 @@ func main() { Fiber defaults to the [html/template](https://pkg.go.dev/html/template/) when no view engine is set. -If you want to execute partials or use a different engine like [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache](https://github.com/cbroglie/mustache) or [pug](https://github.com/Joker/jade) etc.. - -Checkout our [Template](https://github.com/gofiber/template) package that support multiple view engines. +If you want to execute partials or use a different engine like [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache](https://github.com/cbroglie/mustache), or [pug](https://github.com/Joker/jade), etc., check out our [Template](https://github.com/gofiber/template) package that supports multiple view engines. -```go +```go title="Example" package main import ( @@ -278,12 +312,12 @@ import ( ) func main() { - // You can setup Views engine before initiation app: + // Initialize a new Fiber app with Pug template engine app := fiber.New(fiber.Config{ Views: pug.New("./views", ".pug"), }) - // And now, you can call template `./views/home.pug` like this: + // Define a route that renders the "home.pug" template app.Get("/", func(c fiber.Ctx) error { return c.Render("home", fiber.Map{ "title": "Homepage", @@ -295,24 +329,32 @@ func main() { } ``` -### Grouping routes into chains +### Grouping Routes into Chains πŸ“– [Group](https://docs.gofiber.io/api/app#group) -```go +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) + func middleware(c fiber.Ctx) error { - fmt.Println("Don't mind me!") + log.Println("Middleware executed") return c.Next() } func handler(c fiber.Ctx) error { - return c.SendString(c.Path()) + return c.SendString("Handler response") } func main() { app := fiber.New() - // Root API route + // Root API group with middleware api := app.Group("/api", middleware) // /api // API v1 routes @@ -325,16 +367,15 @@ func main() { v2.Get("/list", handler) // /api/v2/list v2.Get("/user", handler) // /api/v2/user - // ... + log.Fatal(app.Listen(":3000")) } - ``` -### Middleware logger +### Middleware Logger πŸ“– [Logger](https://docs.gofiber.io/api/middleware/logger) -```go +```go title="Example" package main import ( @@ -347,9 +388,13 @@ import ( func main() { app := fiber.New() + // Use Logger middleware app.Use(logger.New()) - // ... + // Define routes + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Hello, Logger!") + }) log.Fatal(app.Listen(":3000")) } @@ -359,7 +404,9 @@ func main() { πŸ“– [CORS](https://docs.gofiber.io/api/middleware/cors) -```go +```go title="Example" +package main + import ( "log" @@ -370,9 +417,13 @@ import ( func main() { app := fiber.New() + // Use CORS middleware with default settings app.Use(cors.New()) - // ... + // Define routes + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("CORS enabled!") + }) log.Fatal(app.Listen(":3000")) } @@ -384,28 +435,36 @@ Check CORS by passing any domain in `Origin` header: curl -H "Origin: http://example.com" --verbose http://localhost:3000 ``` -### Custom 404 response +### Custom 404 Response πŸ“– [HTTP Methods](https://docs.gofiber.io/api/ctx#status) -```go +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) + func main() { app := fiber.New() + // Define routes app.Get("/", static.New("./public")) app.Get("/demo", func(c fiber.Ctx) error { - return c.SendString("This is a demo!") + return c.SendString("This is a demo page!") }) app.Post("/register", func(c fiber.Ctx) error { - return c.SendString("Welcome!") + return c.SendString("Registration successful!") }) - // Last middleware to match anything + // Middleware to handle 404 Not Found app.Use(func(c fiber.Ctx) error { - return c.SendStatus(404) - // => 404 "Not Found" + return c.SendStatus(fiber.StatusNotFound) // => 404 "Not Found" }) log.Fatal(app.Listen(":3000")) @@ -416,7 +475,15 @@ func main() { πŸ“– [JSON](https://docs.gofiber.io/api/ctx#json) -```go +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) + type User struct { Name string `json:"name"` Age int `json:"age"` @@ -425,11 +492,13 @@ type User struct { func main() { app := fiber.New() + // Route that returns a JSON object app.Get("/user", func(c fiber.Ctx) error { return c.JSON(&User{"John", 20}) // => {"name":"John", "age":20} }) + // Route that returns a JSON map app.Get("/json", func(c fiber.Ctx) error { return c.JSON(fiber.Map{ "success": true, @@ -446,7 +515,9 @@ func main() { πŸ“– [Websocket](https://github.com/gofiber/websocket) -```go +```go title="Example" +package main + import ( "log" @@ -455,26 +526,31 @@ import ( ) func main() { - app := fiber.New() - - app.Get("/ws", websocket.New(func(c *websocket.Conn) { - for { - mt, msg, err := c.ReadMessage() - if err != nil { - log.Println("read:", err) - break - } - log.Printf("recv: %s", msg) - err = c.WriteMessage(mt, msg) - if err != nil { - log.Println("write:", err) - break - } - } - })) - - log.Fatal(app.Listen(":3000")) - // ws://localhost:3000/ws + app := fiber.New() + + // WebSocket route + app.Get("/ws", websocket.New(func(c *websocket.Conn) { + defer c.Close() + for { + // Read message from client + mt, msg, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + break + } + log.Printf("recv: %s", msg) + + // Write message back to client + err = c.WriteMessage(mt, msg) + if err != nil { + log.Println("write:", err) + break + } + } + })) + + log.Fatal(app.Listen(":3000")) + // Connect via WebSocket at ws://localhost:3000/ws } ``` @@ -482,42 +558,46 @@ func main() { πŸ“– [More Info](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) -```go +```go title="Example" +package main + import ( + "bufio" + "fmt" "log" + "time" "github.com/gofiber/fiber/v3" "github.com/valyala/fasthttp" ) func main() { - app := fiber.New() - - app.Get("/sse", func(c fiber.Ctx) error { - c.Set("Content-Type", "text/event-stream") - c.Set("Cache-Control", "no-cache") - c.Set("Connection", "keep-alive") - c.Set("Transfer-Encoding", "chunked") - - c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) { - fmt.Println("WRITER") - var i int - - for { - i++ - msg := fmt.Sprintf("%d - the time is %v", i, time.Now()) - fmt.Fprintf(w, "data: Message: %s\n\n", msg) - fmt.Println(msg) - - w.Flush() - time.Sleep(5 * time.Second) - } - })) + app := fiber.New() - return nil - }) + // Server-Sent Events route + app.Get("/sse", func(c fiber.Ctx) error { + c.Set("Content-Type", "text/event-stream") + c.Set("Cache-Control", "no-cache") + c.Set("Connection", "keep-alive") + c.Set("Transfer-Encoding", "chunked") + + c.Context().SetBodyStreamWriter(func(w *bufio.Writer) { + var i int + for { + i++ + msg := fmt.Sprintf("%d - the time is %v", i, time.Now()) + fmt.Fprintf(w, "data: Message: %s\n\n", msg) + fmt.Println(msg) + + w.Flush() + time.Sleep(5 * time.Second) + } + }) - log.Fatal(app.Listen(":3000")) + return nil + }) + + log.Fatal(app.Listen(":3000")) } ``` @@ -525,7 +605,9 @@ func main() { πŸ“– [Recover](https://docs.gofiber.io/api/middleware/recover) -```go +```go title="Example" +package main + import ( "log" @@ -536,8 +618,10 @@ import ( func main() { app := fiber.New() + // Use Recover middleware to handle panics gracefully app.Use(recover.New()) + // Route that intentionally panics app.Get("/", func(c fiber.Ctx) error { panic("normally this would crash your app") }) @@ -546,13 +630,13 @@ func main() { } ``` -
- ### Using Trusted Proxy πŸ“– [Config](https://docs.gofiber.io/api/fiber#config) -```go +```go title="Example" +package main + import ( "log" @@ -561,6 +645,7 @@ import ( func main() { app := fiber.New(fiber.Config{ + // Trust all proxies (use with caution) TrustProxy: true, TrustProxyConfig: fiber.TrustProxyConfig{ Proxies: []string{"0.0.0.0", "1.1.1.1/30"}, // IP address or IP address range @@ -568,6 +653,11 @@ func main() { ProxyHeader: fiber.HeaderXForwardedFor, }) + // Define routes + app.Get("/", func(c fiber.Ctx) error { + return c.SendString("Trusted Proxy Configured!") + }) + log.Fatal(app.Listen(":3000")) } ``` @@ -583,14 +673,14 @@ Here is a list of middleware that are included within the Fiber framework. | [adaptor](https://github.com/gofiber/fiber/tree/main/middleware/adaptor) | Converter for net/http handlers to/from Fiber request handlers. | | [basicauth](https://github.com/gofiber/fiber/tree/main/middleware/basicauth) | Provides HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | | [cache](https://github.com/gofiber/fiber/tree/main/middleware/cache) | Intercept and cache HTTP responses. | -| [compress](https://github.com/gofiber/fiber/tree/main/middleware/compress) | Compression middleware for Fiber, with support for `deflate`, `gzip`, `brotli` and `zstd`. | +| [compress](https://github.com/gofiber/fiber/tree/main/middleware/compress) | Compression middleware for Fiber, with support for `deflate`, `gzip`, `brotli` and `zstd`. | | [cors](https://github.com/gofiber/fiber/tree/main/middleware/cors) | Enable cross-origin resource sharing (CORS) with various options. | | [csrf](https://github.com/gofiber/fiber/tree/main/middleware/csrf) | Protect from CSRF exploits. | | [earlydata](https://github.com/gofiber/fiber/tree/main/middleware/earlydata) | Adds support for TLS 1.3's early data ("0-RTT") feature. | | [encryptcookie](https://github.com/gofiber/fiber/tree/main/middleware/encryptcookie) | Encrypt middleware which encrypts cookie values. | | [envvar](https://github.com/gofiber/fiber/tree/main/middleware/envvar) | Expose environment variables with providing an optional config. | | [etag](https://github.com/gofiber/fiber/tree/main/middleware/etag) | Allows for caches to be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. | -| [expvar](https://github.com/gofiber/fiber/tree/main/middleware/expvar) | Serves via its HTTP server runtime exposed variants in the JSON format. | +| [expvar](https://github.com/gofiber/fiber/tree/main/middleware/expvar) | Serves via its HTTP server runtime exposed variables in the JSON format. | | [favicon](https://github.com/gofiber/fiber/tree/main/middleware/favicon) | Ignore favicon from logs or serve from memory if a file path is provided. | | [healthcheck](https://github.com/gofiber/fiber/tree/main/middleware/healthcheck) | Liveness and Readiness probes for Fiber. | | [helmet](https://github.com/gofiber/fiber/tree/main/middleware/helmet) | Helps secure your apps by setting various HTTP headers. | @@ -606,22 +696,22 @@ Here is a list of middleware that are included within the Fiber framework. | [rewrite](https://github.com/gofiber/fiber/tree/main/middleware/rewrite) | Rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | | [session](https://github.com/gofiber/fiber/tree/main/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/main/middleware/skip) | Skip middleware that skips a wrapped handler if a predicate is true. | -| [static](https://github.com/gofiber/fiber/tree/main/middleware/static) | Static middleware for Fiber that serves static files such as **images**, **CSS,** and **JavaScript**. | +| [static](https://github.com/gofiber/fiber/tree/main/middleware/static) | Static middleware for Fiber that serves static files such as **images**, **CSS**, and **JavaScript**. | | [timeout](https://github.com/gofiber/fiber/tree/main/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | ## 🧬 External Middleware List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Description | -| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | -| [contrib](https://github.com/gofiber/contrib) | Third party middlewares | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 9 template engines that can be used with Fiber `v3` Go version 1.22 or higher is required. | +| Middleware | Description | +|-------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------| +| [contrib](https://github.com/gofiber/contrib) | Third-party middlewares | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 9 template engines that can be used with Fiber `v3`. Go version 1.22 or higher is required. | ## πŸ•ΆοΈ Awesome List -For more articles, middlewares, examples or tools check our [awesome list](https://github.com/gofiber/awesome-fiber). +For more articles, middlewares, examples, or tools, check our [awesome list](https://github.com/gofiber/awesome-fiber). ## πŸ‘ Contribute @@ -629,12 +719,12 @@ If you want to say **Thank You** and/or support the active development of `Fiber 1. Add a [GitHub Star](https://github.com/gofiber/fiber/stargazers) to the project. 2. Tweet about the project [on your 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). -3. Write a review or tutorial on [Medium](https://medium.com/), [Dev.to](https://dev.to/) or personal blog. +3. Write a review or tutorial on [Medium](https://medium.com/), [Dev.to](https://dev.to/) or your personal blog. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). -## πŸ–₯️ Development +## πŸ’» Development -To ensure your contributions are ready for a Pull Request, please use the following `Makefile` commands. These tools help maintain code quality, consistency. +To ensure your contributions are ready for a Pull Request, please use the following `Makefile` commands. These tools help maintain code quality and consistency. - **make help**: Display available commands. - **make audit**: Conduct quality checks. @@ -649,22 +739,22 @@ Run these commands to ensure your code adheres to project standards and best pra ## β˜• Supporters -Fiber is an open source project that runs on donations to pay the bills e.g. our domain name, gitbook, netlify and serverless hosting. If you want to support Fiber, you can β˜• [**buy a coffee here**](https://buymeacoff.ee/fenny). +Fiber is an open-source project that runs on donations to pay the bills, e.g., our domain name, GitBook, Netlify, and serverless hosting. If you want to support Fiber, you can β˜• [**buy a coffee here**](https://buymeacoff.ee/fenny). | | User | Donation | -| :--------------------------------------------------------- | :----------------------------------------------- | :------- | -| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | β˜• x 10 | -| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | β˜• x 5 | -| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | β˜• x 5 | -| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | β˜• x 5 | -| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | β˜• x 5 | -| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | β˜• x 5 | -| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | β˜• x 5 | -| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | β˜• x 3 | -| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | β˜• x 3 | -| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | β˜• x 3 | -| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | β˜• x 1 | -| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | β˜• x 1 | +| ---------------------------------------------------------- | ------------------------------------------------ | -------- | +| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | β˜• x 10 | +| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | β˜• x 5 | +| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | β˜• x 5 | +| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | β˜• x 5 | +| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | β˜• x 5 | +| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | β˜• x 5 | +| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | β˜• x 5 | +| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | β˜• x 3 | +| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | β˜• x 3 | +| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | β˜• x 3 | +| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | β˜• x 1 | +| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | β˜• x 1 | | ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | β˜• x 1 | | ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | β˜• x 1 | | ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | β˜• x 1 | diff --git a/docs/api/app.md b/docs/api/app.md index ef9c2ea08d..8223398887 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -17,18 +17,28 @@ import RoutingHandler from './../partials/routing/handler.md'; ### Mounting -You can Mount Fiber instance using the [`app.Use`](./app.md#use) method similar to [`express`](https://expressjs.com/en/api.html#router.use). +You can mount a Fiber instance using the [`app.Use`](./app.md#use) method, similar to [`Express`](https://expressjs.com/en/api.html#router.use). + +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) -```go title="Examples" func main() { app := fiber.New() micro := fiber.New() + + // Mount the micro app on the "/john" route app.Use("/john", micro) // GET /john/doe -> 200 OK - + micro.Get("/doe", func(c fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) }) - + log.Fatal(app.Listen(":3000")) } ``` @@ -40,8 +50,16 @@ The `MountPath` property contains one or more path patterns on which a sub-app w ```go title="Signature" func (app *App) MountPath() string ``` + +```go title="Example" +package main + +import ( + "fmt" + + "github.com/gofiber/fiber/v3" +) -```go title="Examples" func main() { app := fiber.New() one := fiber.New() @@ -51,16 +69,17 @@ func main() { 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() // "" + + fmt.Println("Mount paths:") + fmt.Println("one.MountPath():", one.MountPath()) // "/one" + fmt.Println("two.MountPath():", two.MountPath()) // "/one/two" + fmt.Println("three.MountPath():", three.MountPath()) // "/one/two/three" + fmt.Println("app.MountPath():", app.MountPath()) // "" } ``` :::caution -Mounting order is important for MountPath. If you want to get mount paths properly, you should start mounting from the deepest app. +Mounting order is important for `MountPath`. To get mount paths properly, you should start mounting from the deepest app. ::: ### Group @@ -70,22 +89,34 @@ You can group routes by creating a `*Group` struct. ```go title="Signature" func (app *App) Group(prefix string, handlers ...Handler) Router ``` + +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) -```go title="Examples" func main() { - app := fiber.New() + app := fiber.New() + + api := app.Group("/api", handler) // /api - api := app.Group("/api", handler) // /api + v1 := api.Group("/v1", handler) // /api/v1 + v1.Get("/list", handler) // /api/v1/list + v1.Get("/user", handler) // /api/v1/user - v1 := api.Group("/v1", handler) // /api/v1 - v1.Get("/list", handler) // /api/v1/list - v1.Get("/user", handler) // /api/v1/user + v2 := api.Group("/v2", handler) // /api/v2 + v2.Get("/list", handler) // /api/v2/list + v2.Get("/user", handler) // /api/v2/user - v2 := api.Group("/v2", handler) // /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")) +func handler(c fiber.Ctx) error { + return c.SendString("Handler response") } ``` @@ -104,64 +135,73 @@ func (app *App) Route(path string) Register ```go type Register interface { - All(handler Handler, middleware ...Handler) Register - Get(handler Handler, middleware ...Handler) Register - Head(handler Handler, middleware ...Handler) Register - Post(handler Handler, middleware ...Handler) Register - Put(handler Handler, middleware ...Handler) Register - Delete(handler Handler, middleware ...Handler) Register - Connect(handler Handler, middleware ...Handler) Register - Options(handler Handler, middleware ...Handler) Register - Trace(handler Handler, middleware ...Handler) Register - Patch(handler Handler, middleware ...Handler) Register - - Add(methods []string, handler Handler, middleware ...Handler) Register - - Route(path string) Register + All(handler Handler, middleware ...Handler) Register + Get(handler Handler, middleware ...Handler) Register + Head(handler Handler, middleware ...Handler) Register + Post(handler Handler, middleware ...Handler) Register + Put(handler Handler, middleware ...Handler) Register + Delete(handler Handler, middleware ...Handler) Register + Connect(handler Handler, middleware ...Handler) Register + Options(handler Handler, middleware ...Handler) Register + Trace(handler Handler, middleware ...Handler) Register + Patch(handler Handler, middleware ...Handler) Register + + Add(methods []string, handler Handler, middleware ...Handler) Register + + Route(path string) Register } ``` -```go title="Examples" +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) + func main() { - app := fiber.New() - - // use `Route` as chainable route declaration method - app.Route("/test").Get(func(c fiber.Ctx) error { - return c.SendString("GET /test") - }) - - app.Route("/events").all(func(c fiber.Ctx) error { - // runs for all HTTP verbs first - // think of it as route specific middleware! - }) - .get(func(c fiber.Ctx) error { - return c.SendString("GET /events") - }) - .post(func(c fiber.Ctx) error { - // maybe add a new event... - }) - - // combine multiple routes - app.Route("/v2").Route("/user").Get(func(c fiber.Ctx) error { - return c.SendString("GET /v2/user") - }) - - // use multiple methods - app.Route("/api").Get(func(c fiber.Ctx) error { - return c.SendString("GET /api") - }).Post(func(c fiber.Ctx) error { - return c.SendString("POST /api") - }) - - log.Fatal(app.Listen(":3000")) + app := fiber.New() + + // Use `Route` as a chainable route declaration method + app.Route("/test").Get(func(c fiber.Ctx) error { + return c.SendString("GET /test") + }) + + app.Route("/events").All(func(c fiber.Ctx) error { + // Runs for all HTTP verbs first + // Think of it as route-specific middleware! + }). + Get(func(c fiber.Ctx) error { + return c.SendString("GET /events") + }). + Post(func(c fiber.Ctx) error { + // Maybe add a new event... + return c.SendString("POST /events") + }) + + // Combine multiple routes + app.Route("/v2").Route("/user").Get(func(c fiber.Ctx) error { + return c.SendString("GET /v2/user") + }) + + // Use multiple methods + app.Route("/api").Get(func(c fiber.Ctx) error { + return c.SendString("GET /api") + }).Post(func(c fiber.Ctx) error { + return c.SendString("POST /api") + }) + + log.Fatal(app.Listen(":3000")) } ``` ### HandlersCount -This method returns the amount of registered handlers. +This method returns the number of registered handlers. ```go title="Signature" func (app *App) HandlersCount() uint32 @@ -169,14 +209,21 @@ func (app *App) HandlersCount() uint32 ### Stack -This method returns the original router stack +This method returns the original router stack. ```go title="Signature" func (app *App) Stack() [][]*Route ``` -```go title="Examples" -var handler = func(c fiber.Ctx) error { return nil } +```go title="Example" +package main + +import ( + "encoding/json" + "log" + + "github.com/gofiber/fiber/v3" +) func main() { app := fiber.New() @@ -184,10 +231,10 @@ func main() { app.Get("/john/:age", handler) app.Post("/register", handler) - data, _ := json.MarshalIndent(app.Stack(), "", " ") + data, _err_ := json.MarshalIndent(app.Stack(), "", " ") fmt.Println(string(data)) - app.Listen(":3000") + log.Fatal(app.Listen(":3000")) } ``` @@ -228,25 +275,32 @@ func main() { ### Name -This method assigns the name of latest created route. +This method assigns the name to the latest created route. ```go title="Signature" func (app *App) Name(name string) Router ``` -```go title="Examples" -var handler = func(c fiber.Ctx) error { return nil } +```go title="Example" +package main + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/gofiber/fiber/v3" +) func main() { + var handler = func(c fiber.Ctx) error { return nil } + app := fiber.New() app.Get("/", handler) app.Name("index") - app.Get("/doe", handler).Name("home") - app.Trace("/tracer", handler).Name("tracert") - app.Delete("/delete", handler).Name("delete") a := app.Group("/a") @@ -255,10 +309,9 @@ func main() { a.Get("/test", handler).Name("test") data, _ := json.MarshalIndent(app.Stack(), "", " ") - fmt.Print(string(data)) - - app.Listen(":3000") + fmt.Println(string(data)) + log.Fatal(app.Listen(":3000")) } ``` @@ -335,25 +388,34 @@ func main() { ### GetRoute -This method gets the route by name. +This method retrieves a route by its name. ```go title="Signature" func (app *App) GetRoute(name string) Route ``` -```go title="Examples" -var handler = func(c fiber.Ctx) error { return nil } +```go title="Example" +package main + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/gofiber/fiber/v3" +) func main() { app := fiber.New() app.Get("/", handler).Name("index") - data, _ := json.MarshalIndent(app.GetRoute("index"), "", " ") - fmt.Print(string(data)) + route := app.GetRoute("index") + data, _ := json.MarshalIndent(route, "", " ") + fmt.Println(string(data)) - app.Listen(":3000") + log.Fatal(app.Listen(":3000")) } ``` @@ -373,22 +435,38 @@ func main() { ### GetRoutes -This method gets all routes. +This method retrieves all routes. ```go title="Signature" func (app *App) GetRoutes(filterUseOption ...bool) []Route ``` -When filterUseOption equal to true, it will filter the routes registered by the middleware. +When `filterUseOption` is set to `true`, it filters out routes registered by middleware. + +```go title="Example" +package main + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/gofiber/fiber/v3" +) -```go title="Examples" func main() { app := fiber.New() - app.Post("/", func (c fiber.Ctx) error { + + app.Post("/", func(c fiber.Ctx) error { return c.SendString("Hello, World!") }).Name("index") - data, _ := json.MarshalIndent(app.GetRoutes(true), "", " ") - fmt.Print(string(data)) + + routes := app.GetRoutes(true) + + data, _ := json.MarshalIndent(routes, "", " ") + fmt.Println(string(data)) + + log.Fatal(app.Listen(":3000")) } ``` @@ -410,7 +488,7 @@ func main() { ## Config -Config returns the [app config](./fiber.md#config) as value \( read-only \). +`Config` returns the [app config](./fiber.md#config) as a value (read-only). ```go title="Signature" func (app *App) Config() Config @@ -418,7 +496,7 @@ func (app *App) Config() Config ## Handler -Handler returns the server handler that can be used to serve custom [`\*fasthttp.RequestCtx`](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) requests. +`Handler` returns the server handler that can be used to serve custom [`*fasthttp.RequestCtx`](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) requests. ```go title="Signature" func (app *App) Handler() fasthttp.RequestHandler @@ -426,7 +504,7 @@ func (app *App) Handler() fasthttp.RequestHandler ## ErrorHandler -Errorhandler executes the process which was defined for the application in case of errors, this is used in some cases in middlewares. +`ErrorHandler` executes the process defined for the application in case of errors. This is used in some cases in middlewares. ```go title="Signature" func (app *App) ErrorHandler(ctx Ctx, err error) error @@ -434,15 +512,23 @@ func (app *App) ErrorHandler(ctx Ctx, err error) error ## NewCtxFunc -NewCtxFunc allows to customize the ctx struct as we want. +`NewCtxFunc` allows you to customize the `ctx` struct as needed. ```go title="Signature" func (app *App) NewCtxFunc(function func(app *App) CustomCtx) ``` -```go title="Examples" +```go title="Example" +package main + +import ( + "fmt" + + "github.com/gofiber/fiber/v3" +) + type CustomCtx struct { - DefaultCtx + fiber.DefaultCtx } // Custom method @@ -450,125 +536,156 @@ func (c *CustomCtx) Params(key string, defaultValue ...string) string { return "prefix_" + c.DefaultCtx.Params(key) } -app := New() -app.NewCtxFunc(func(app *fiber.App) fiber.CustomCtx { - return &CustomCtx{ - DefaultCtx: *NewDefaultCtx(app), - } -}) -// curl http://localhost:3000/123 -app.Get("/:id", func(c Ctx) error { - // use custom method - output: prefix_123 - return c.SendString(c.Params("id")) -}) +func main() { + app := fiber.New() + + app.NewCtxFunc(func(app *fiber.App) fiber.CustomCtx { + return &CustomCtx{ + DefaultCtx: *fiber.NewDefaultCtx(app), + } + }) + + app.Get("/:id", func(c fiber.Ctx) error { + // Use custom method - output: prefix_123 + return c.SendString(c.Params("id")) + }) + + log.Fatal(app.Listen(":3000")) +} ``` ## RegisterCustomBinder -You can register custom binders to use as [`Bind().Custom("name")`](bind.md#custom). -They should be compatible with CustomBinder interface. +You can register custom binders to use with [`Bind().Custom("name")`](bind.md#custom). They should be compatible with the `CustomBinder` interface. ```go title="Signature" func (app *App) RegisterCustomBinder(binder CustomBinder) ``` -```go title="Examples" -app := fiber.New() +```go title="Example" +package main + +import ( + "log" -// My custom binder -customBinder := &customBinder{} -// Name of custom binder, which will be used as Bind().Custom("name") -func (*customBinder) Name() string { + "github.com/gofiber/fiber/v3" + "gopkg.in/yaml.v2" +) + +type User struct { + Name string `yaml:"name"` +} + +type customBinder struct{} + +func (cb *customBinder) Name() string { return "custom" } -// Is used in the Body Bind method to check if the binder should be used for custom mime types -func (*customBinder) MIMETypes() []string { + +func (cb *customBinder) MIMETypes() []string { return []string{"application/yaml"} } -// Parse the body and bind it to the out interface -func (*customBinder) Parse(c Ctx, out any) error { - // parse yaml body + +func (cb *customBinder) Parse(c fiber.Ctx, out any) error { + // Parse YAML body return yaml.Unmarshal(c.Body(), out) } -// Register custom binder -app.RegisterCustomBinder(customBinder) - -// curl -X POST http://localhost:3000/custom -H "Content-Type: application/yaml" -d "name: John" -app.Post("/custom", func(c Ctx) error { - var user User - // output: {Name:John} - // Custom binder is used by the name - if err := c.Bind().Custom("custom", &user); err != nil { - return err - } - // ... - return c.JSON(user) -}) -// curl -X POST http://localhost:3000/normal -H "Content-Type: application/yaml" -d "name: Doe" -app.Post("/normal", func(c Ctx) error { - var user User - // output: {Name:Doe} - // Custom binder is used by the mime type - if err := c.Bind().Body(&user); err != nil { - return err - } - // ... - return c.JSON(user) -}) + +func main() { + app := fiber.New() + + // Register custom binder + app.RegisterCustomBinder(&customBinder{}) + + app.Post("/custom", func(c fiber.Ctx) error { + var user User + // Use Custom binder by name + if err := c.Bind().Custom("custom", &user); err != nil { + return err + } + return c.JSON(user) + }) + + app.Post("/normal", func(c fiber.Ctx) error { + var user User + // Custom binder is used by the MIME type + if err := c.Bind().Body(&user); err != nil { + return err + } + return c.JSON(user) + }) + + log.Fatal(app.Listen(":3000")) +} ``` ## RegisterCustomConstraint -RegisterCustomConstraint allows to register custom constraint. - +`RegisterCustomConstraint` allows you to register custom constraints. + ```go title="Signature" func (app *App) RegisterCustomConstraint(constraint CustomConstraint) ``` -See [Custom Constraint](../guide/routing.md#custom-constraint) section for more information. +See the [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. - +Use `SetTLSHandler` to set [`ClientHelloInfo`](https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2) when using TLS with a `Listener`. + ```go title="Signature" func (app *App) SetTLSHandler(tlsHandler *TLSHandler) ``` ## Test -Testing your application is done with the **Test** method. Use this method for creating `_test.go` files or when you need to debug your routing logic. The default timeout is `1s` if you want to disable a timeout altogether, pass `-1` as a second argument. +Testing your application is done with the `Test` method. Use this method for creating `_test.go` files or when you need to debug your routing logic. The default timeout is `1s`; to disable a timeout altogether, pass `-1` as the second argument. ```go title="Signature" func (app *App) Test(req *http.Request, msTimeout ...int) (*http.Response, error) ``` -```go title="Examples" -// Create route with GET method for test: -app.Get("/", func(c fiber.Ctx) error { - fmt.Println(c.BaseURL()) // => http://google.com - fmt.Println(c.Get("X-Custom-Header")) // => hi +```go title="Example" +package main + +import ( + "fmt" + "io" + "log" + "net/http" + "net/http/httptest" - return c.SendString("hello, World!") -}) + "github.com/gofiber/fiber/v3" +) + +func main() { + app := fiber.New() + + // Create route with GET method for test: + app.Get("/", func(c fiber.Ctx) error { + fmt.Println(c.BaseURL()) // => http://google.com + fmt.Println(c.Get("X-Custom-Header")) // => hi + return c.SendString("hello, World!") + }) -// http.Request -req := httptest.NewRequest("GET", "http://google.com", nil) -req.Header.Set("X-Custom-Header", "hi") + // Create http.Request + req := httptest.NewRequest("GET", "http://google.com", nil) + req.Header.Set("X-Custom-Header", "hi") -// http.Response -resp, _ := app.Test(req) + // Perform the test + resp, _ := app.Test(req) -// Do something with results: -if resp.StatusCode == fiber.StatusOK { - body, _ := io.ReadAll(resp.Body) - fmt.Println(string(body)) // => Hello, World! + // Do something with the results: + if resp.StatusCode == fiber.StatusOK { + body, _ := io.ReadAll(resp.Body) + fmt.Println(string(body)) // => hello, World! + } } ``` ## Hooks -Hooks is a method to return [hooks](./hooks.md) property. +`Hooks` is a method to return the [hooks](./hooks.md) property. ```go title="Signature" func (app *App) Hooks() *Hooks @@ -576,7 +693,7 @@ func (app *App) Hooks() *Hooks ## RebuildTree -The RebuildTree method is designed to rebuild the route tree and enable dynamic route registration. It returns a pointer to the App instance. +The `RebuildTree` method is designed to rebuild the route tree and enable dynamic route registration. It returns a pointer to the `App` instance. ```go title="Signature" func (app *App) RebuildTree() *App @@ -588,16 +705,32 @@ func (app *App) RebuildTree() *App Here’s an example of how to define and register routes dynamically: -```go -app.Get("/define", func(c Ctx) error { // Define a new route dynamically - app.Get("/dynamically-defined", func(c Ctx) error { // Adding a dynamically defined route - return c.SendStatus(http.StatusOK) - }) +```go title="Example" +package main + +import ( + "log" + + "github.com/gofiber/fiber/v3" +) + +func main() { + app := fiber.New() + + app.Get("/define", func(c fiber.Ctx) error { + // Define a new route dynamically + app.Get("/dynamically-defined", func(c fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) - app.RebuildTree() // Rebuild the route tree to register the new route + // Rebuild the route tree to register the new route + app.RebuildTree() - return c.SendStatus(http.StatusOK) -}) + return c.SendStatus(fiber.StatusOK) + }) + + log.Fatal(app.Listen(":3000")) +} ``` -In this example, a new route is defined and then `RebuildTree()` is called to make sure the new route is registered and available. +In this example, a new route is defined and then `RebuildTree()` is called to ensure the new route is registered and available. diff --git a/docs/api/bind.md b/docs/api/bind.md index 73256cbbb8..d72a9009c7 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -6,13 +6,11 @@ sidebar_position: 4 toc_max_heading_level: 4 --- -Bindings are used to parse the request/response body, query parameters, cookies and much more into a struct. +Bindings are used to parse the request/response body, query parameters, cookies, and much more into a struct. :::info - -All binder returned value are only valid within the handler. Do not store any references. +All binder returned values are only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) - ::: ## Binders @@ -32,22 +30,21 @@ Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more.. Binds the request 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"`. +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 with `json:"pass"`. -| content-type | struct tag | +| Content-Type | Struct Tag | | ----------------------------------- | ---------- | -| `application/x-www-form-urlencoded` | form | -| `multipart/form-data` | form | -| `application/json` | json | -| `application/xml` | xml | -| `text/xml` | xml | +| `application/x-www-form-urlencoded` | `form` | +| `multipart/form-data` | `form` | +| `application/json` | `json` | +| `application/xml` | `xml` | +| `text/xml` | `xml` | ```go title="Signature" func (b *Bind) Body(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { Name string `json:"name" xml:"name" form:"name"` Pass string `json:"pass" xml:"pass" form:"pass"` @@ -65,34 +62,35 @@ app.Post("/", func(c fiber.Ctx) error { // ... }) +``` -// Run tests with the following curl commands - -// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000 +Run tests with the following `curl` commands: -// curl -X POST -H "Content-Type: application/xml" --data "johndoe" localhost:3000 +```bash +# JSON +curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000 -// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000 +# XML +curl -X POST -H "Content-Type: application/xml" --data "johndoe" localhost:3000 -// curl -X POST -F name=john -F pass=doe http://localhost:3000 +# Form URL-Encoded +curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000 -// curl -X POST "http://localhost:3000/?name=john&pass=doe" +# Multipart Form +curl -X POST -F name=john -F pass=doe http://localhost:3000 ``` -**The methods for the various bodies can also be used directly:** - -#### Form +### Form 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"`. +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 with `form:"pass"`. ```go title="Signature" func (b *Bind) Form(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { Name string `form:"name"` Pass string `form:"pass"` @@ -110,24 +108,25 @@ app.Post("/", func(c fiber.Ctx) error { // ... }) +``` -// Run tests with the following curl commands +Run tests with the following `curl` command: -// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000 +```bash +curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000 ``` -#### JSON +### JSON -Binds the request json body to a struct. +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"`. +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 with `json:"pass"`. ```go title="Signature" func (b *Bind) JSON(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { Name string `json:"name"` Pass string `json:"pass"` @@ -145,25 +144,25 @@ app.Post("/", func(c fiber.Ctx) error { // ... }) +``` -// Run tests with the following curl commands - -// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000 +Run tests with the following `curl` command: +```bash +curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000 ``` -#### MultipartForm +### MultipartForm 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"`. +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 multipart form body with a field called `Pass`, you would use a struct field with `form:"pass"`. ```go title="Signature" func (b *Bind) MultipartForm(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { Name string `form:"name"` Pass string `form:"pass"` @@ -181,25 +180,25 @@ app.Post("/", func(c fiber.Ctx) error { // ... }) +``` -// Run tests with the following curl commands - -// curl -X POST -H "Content-Type: multipart/form-data" -F "name=john" -F "pass=doe" localhost:3000 +Run tests with the following `curl` command: +```bash +curl -X POST -H "Content-Type: multipart/form-data" -F "name=john" -F "pass=doe" localhost:3000 ``` -#### XML +### XML -Binds the request xml form body to a struct. +Binds the request XML 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 an 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 with `xml:"pass"`. ```go title="Signature" func (b *Bind) XML(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { Name string `xml:"name"` Pass string `xml:"pass"` @@ -217,27 +216,28 @@ app.Post("/", func(c fiber.Ctx) error { // ... }) +``` -// Run tests with the following curl commands +Run tests with the following `curl` command: -// curl -X POST -H "Content-Type: application/xml" --data "johndoe" localhost:3000 +```bash +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. -It is important to use the struct tag "cookie". For example, if you want to parse a cookie with a field called Age, you would use a struct field of `cookie:"age"`. +This method is similar to [Body Binding](#body), but for cookie parameters. +It is important to use the struct tag `cookie`. For example, if you want to parse a cookie with a field called `Age`, you would use a struct field with `cookie:"age"`. ```go title="Signature" func (b *Bind) Cookie(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { - Name string `cookie:"name"` - Age int `cookie:"age"` - Job bool `cookie:"job"` + Name string `cookie:"name"` + Age int `cookie:"age"` + Job bool `cookie:"job"` } app.Get("/", func(c fiber.Ctx) error { @@ -247,29 +247,32 @@ app.Get("/", func(c fiber.Ctx) error { return err } - log.Println(p.Name) // Joseph - log.Println(p.Age) // 23 - log.Println(p.Job) // true + log.Println(p.Name) // Joseph + log.Println(p.Age) // 23 + log.Println(p.Job) // true }) -// Run tests with the following curl command -// curl.exe --cookie "name=Joseph; age=23; job=true" http://localhost:8000/ +``` + +Run tests with the following `curl` command: + +```bash +curl --cookie "name=Joseph; age=23; job=true" http://localhost:8000/ ``` ### Header -This method is similar to [Body-Binding](#body), but for request headers. -It is important to use the struct tag "header". For example, if you want to parse a request header with a field called Pass, you would use a struct field of `header:"pass"`. +This method is similar to [Body Binding](#body), but for request headers. +It is important to use the struct tag `header`. For example, if you want to parse a request header with a field called `Pass`, you would use a struct field with `header:"pass"`. ```go title="Signature" func (b *Bind) Header(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { - Name string `header:"name"` - Pass string `header:"pass"` - Products []string `header:"products"` + Name string `header:"name"` + Pass string `header:"pass"` + Products []string `header:"products"` } app.Get("/", func(c fiber.Ctx) error { @@ -281,30 +284,32 @@ app.Get("/", func(c fiber.Ctx) error { log.Println(p.Name) // john log.Println(p.Pass) // doe - log.Println(p.Products) // [shoe, hat] + log.Println(p.Products) // [shoe hat] // ... }) -// Run tests with the following curl command +``` + +Run tests with the following `curl` command: -// curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat" +```bash +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. -It is important to use the struct tag "query". For example, if you want to parse a query parameter with a field called Pass, you would use a struct field of `query:"pass"`. +This method is similar to [Body Binding](#body), but for query parameters. +It is important to use the struct tag `query`. For example, if you want to parse a query parameter with a field called `Pass`, you would use a struct field with `query:"pass"`. ```go title="Signature" func (b *Bind) Query(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { - Name string `query:"name"` - Pass string `query:"pass"` - Products []string `query:"products"` + Name string `query:"name"` + Pass string `query:"pass"` + Products []string `query:"products"` } app.Get("/", func(c fiber.Ctx) error { @@ -314,40 +319,41 @@ app.Get("/", func(c fiber.Ctx) error { return err } - log.Println(p.Name) // john - log.Println(p.Pass) // doe - // fiber.Config{EnableSplittingOnParsers: false} - default - log.Println(p.Products) // ["shoe,hat"] - // fiber.Config{EnableSplittingOnParsers: true} + log.Println(p.Name) // john + log.Println(p.Pass) // doe + // Depending on fiber.Config{EnableSplittingOnParsers: false} - default + log.Println(p.Products) // ["shoe,hat"] + // With fiber.Config{EnableSplittingOnParsers: true} // log.Println(p.Products) // ["shoe", "hat"] - // ... }) -// Run tests with the following curl command +``` + +Run tests with the following `curl` command: -// curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" +```bash +curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat" ``` :::info -For more parser settings please look here [Config](fiber.md#enablesplittingonparsers) +For more parser settings, please refer to [Config](fiber.md#enablesplittingonparsers) ::: ### RespHeader -This method is similar to [Body-Binding](#body), but for response headers. -It is important to use the struct tag "respHeader". For example, if you want to parse a request header with a field called Pass, you would use a struct field of `respHeader:"pass"`. +This method is similar to [Body Binding](#body), but for response headers. +It is important to use the struct tag `respHeader`. For example, if you want to parse a response header with a field called `Pass`, you would use a struct field with `respHeader:"pass"`. ```go title="Signature" -func (b *Bind) Header(out any) error +func (b *Bind) RespHeader(out any) error ``` ```go title="Example" -// Field names should start with an uppercase letter type Person struct { - Name string `respHeader:"name"` - Pass string `respHeader:"pass"` - Products []string `respHeader:"products"` + Name string `respHeader:"name"` + Pass string `respHeader:"pass"` + Products []string `respHeader:"products"` } app.Get("/", func(c fiber.Ctx) error { @@ -359,18 +365,22 @@ app.Get("/", func(c fiber.Ctx) error { log.Println(p.Name) // john log.Println(p.Pass) // doe - log.Println(p.Products) // [shoe, hat] + log.Println(p.Products) // [shoe hat] // ... }) -// Run tests with the following curl command +``` + +Run tests with the following `curl` command: -// curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat" +```bash +curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat" ``` ### URI -This method is similar to [Body-Binding](#body), but for path parameters. It is important to use the struct tag "uri". For example, if you want to parse a path parameter with a field called Pass, you would use a struct field of uri:"pass" +This method is similar to [Body Binding](#body), but for path parameters. +It is important to use the struct tag `uri`. For example, if you want to parse a path parameter with a field called `Pass`, you would use a struct field with `uri:"pass"`. ```go title="Signature" func (b *Bind) URI(out any) error @@ -379,20 +389,24 @@ func (b *Bind) URI(out any) error ```go title="Example" // GET http://example.com/user/111 app.Get("/user/:id", func(c fiber.Ctx) error { - param := struct {ID uint `uri:"id"`}{} + param := struct { + ID uint `uri:"id"` + }{} - c.Bind().URI(¶m) // "{"id": 111}" + if err := c.Bind().URI(¶m); err != nil { + return err + } // ... + return c.SendString(fmt.Sprintf("User ID: %d", param.ID)) }) - ``` ## Custom To use custom binders, you have to use this method. -You can register them from [RegisterCustomBinder](./app.md#registercustombinder) method of Fiber instance. +You can register them using the [RegisterCustomBinder](./app.md#registercustombinder) method of the Fiber instance. ```go title="Signature" func (b *Bind) Custom(name string, dest any) error @@ -402,56 +416,65 @@ func (b *Bind) Custom(name string, dest any) error app := fiber.New() // My custom binder -customBinder := &customBinder{} -// Name of custom binder, which will be used as Bind().Custom("name") -func (*customBinder) Name() string { +type customBinder struct{} + +func (cb *customBinder) Name() string { return "custom" } -// Is used in the Body Bind method to check if the binder should be used for custom mime types -func (*customBinder) MIMETypes() []string { + +func (cb *customBinder) MIMETypes() []string { return []string{"application/yaml"} } -// Parse the body and bind it to the out interface -func (*customBinder) Parse(c Ctx, out any) error { - // parse yaml body + +func (cb *customBinder) Parse(c fiber.Ctx, out any) error { + // parse YAML body return yaml.Unmarshal(c.Body(), out) } + // Register custom binder -app.RegisterCustomBinder(customBinder) +app.RegisterCustomBinder(&customBinder{}) -// curl -X POST http://localhost:3000/custom -H "Content-Type: application/yaml" -d "name: John" -app.Post("/custom", func(c Ctx) error { +type User struct { + Name string `yaml:"name"` +} + +app.Post("/custom", func(c fiber.Ctx) error { var user User - // output: {Name:John} - // Custom binder is used by the name + // Use Custom binder by name if err := c.Bind().Custom("custom", &user); err != nil { return err } - // ... return c.JSON(user) }) ``` -Internally they are also used in the [Body](#body) method. -For this the MIMETypes method is used to check if the custom binder should be used for the given content type. +Internally, custom binders are also used in the [Body](#body) method. +The `MIMETypes` method is used to check if the custom binder should be used for the given content type. ## Options -For more control over the error handling, you can use the following methods. +For more control over error handling, you can use the following methods. ### Must -If you want to handle binder errors automatically, you can use Must. -If there's an error it'll return error and 400 as HTTP status. +If you want to handle binder errors automatically, you can use `Must`. +If there's an error, it will return the error and set HTTP status to `400 Bad Request`. ```go title="Signature" func (b *Bind) Must() *Bind ``` +```go title="Example" +app.Get("/coffee", func(c fiber.Ctx) error { + // => HTTP - GET 301 /teapot + return c.Redirect().Status(fiber.StatusMovedPermanently).To("/teapot") +}) +``` + ### Should -To handle binder errors manually, you can prefer Should method. -It's default behavior of binder. +To handle binder errors manually, you can use the `Should` method. +It's the default behavior of the binder. ```go title="Signature" func (b *Bind) Should() *Bind @@ -459,7 +482,7 @@ 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. +Allows you to configure the BodyParser/QueryParser decoder based on schema options, providing the possibility to add custom types for parsing. ```go title="Signature" func SetParserDecoder(parserConfig fiber.ParserConfig{ @@ -477,34 +500,34 @@ func SetParserDecoder(parserConfig fiber.ParserConfig{ type CustomTime time.Time -// String() returns the time in string +// String returns the time in string format func (ct *CustomTime) String() string { t := time.Time(*ct).String() - return t - } - - // Register the converter for CustomTime type format as 2006-01-02 - var timeConverter = func(value string) reflect.Value { - fmt.Println("timeConverter", value) + return t +} + +// Converter for CustomTime type with format "2006-01-02" +var timeConverter = func(value string) reflect.Value { + fmt.Println("timeConverter:", value) if v, err := time.Parse("2006-01-02", value); err == nil { - return reflect.ValueOf(v) + return reflect.ValueOf(CustomTime(v)) } return reflect.Value{} } customTime := fiber.ParserType{ - Customtype: CustomTime{}, + CustomType: CustomTime{}, Converter: timeConverter, } -// Add setting to the Decoder +// Add custom type to the Decoder settings fiber.SetParserDecoder(fiber.ParserConfig{ IgnoreUnknownKeys: true, ParserType: []fiber.ParserType{customTime}, ZeroEmpty: true, }) -// Example to use CustomType, you pause custom time format not in RFC3339 +// Example using CustomTime with non-RFC3339 format type Demo struct { Date CustomTime `form:"date" query:"date"` Title string `form:"title" query:"title"` @@ -513,31 +536,38 @@ type Demo struct { app.Post("/body", func(c fiber.Ctx) error { var d Demo - c.BodyParser(&d) - fmt.Println("d.Date", d.Date.String()) + if err := c.Bind().Body(&d); err != nil { + return err + } + fmt.Println("d.Date:", d.Date.String()) return c.JSON(d) }) app.Get("/query", func(c fiber.Ctx) error { var d Demo - c.QueryParser(&d) - fmt.Println("d.Date", d.Date.String()) + if err := c.Bind().Query(&d); err != nil { + return err + } + fmt.Println("d.Date:", d.Date.String()) return c.JSON(d) }) -// curl -X POST -F title=title -F body=body -F date=2021-10-20 http://localhost:3000/body +// Run tests with the following curl commands: -// curl -X GET "http://localhost:3000/query?title=title&body=body&date=2021-10-20" +# Body Binding +curl -X POST -F title=title -F body=body -F date=2021-10-20 http://localhost:3000/body +# Query Binding +curl -X GET "http://localhost:3000/query?title=title&body=body&date=2021-10-20" ``` ## Validation Validation is also possible with the binding methods. You can specify your validation rules using the `validate` struct tag. -Specify your struct validator in the [config](./fiber.md#structvalidator) +Specify your struct validator in the [config](./fiber.md#structvalidator). -Setup your validator in the config: +### Setup Your Validator in the Config ```go title="Example" import "github.com/go-playground/validator/v10" @@ -546,18 +576,18 @@ type structValidator struct { validate *validator.Validate } -// Validator needs to implement the Validate method +// Validate method implementation func (v *structValidator) Validate(out any) error { return v.validate.Struct(out) } -// Setup your validator in the config +// Setup your validator in the Fiber config app := fiber.New(fiber.Config{ StructValidator: &structValidator{validate: validator.New()}, }) ``` -Usage of the validation in the binding methods: +### Usage of Validation in Binding Methods ```go title="Example" type Person struct { @@ -568,7 +598,7 @@ type Person struct { app.Post("/", func(c fiber.Ctx) error { p := new(Person) - if err := c.Bind().JSON(p); err != nil {// <- here you receive the validation errors + if err := c.Bind().JSON(p); err != nil { // Receives validation errors return err } }) @@ -578,19 +608,19 @@ app.Post("/", func(c fiber.Ctx) error { You can set default values for fields in the struct by using the `default` struct tag. Supported types: -- bool -- float variants (float32, float64) -- int variants (int, int8, int16, int32, int64) -- uint variants (uint, uint8, uint16, uint32, uint64) -- string -- a slice of the above types. As shown in the example above, **| should be used to separate between slice items**. -- a pointer to one of the above types **(pointer to slice and slice of pointers are not supported)**. +- `bool` +- Float variants (`float32`, `float64`) +- Int variants (`int`, `int8`, `int16`, `int32`, `int64`) +- Uint variants (`uint`, `uint8`, `uint16`, `uint32`, `uint64`) +- `string` +- A slice of the above types. Use `|` to separate slice items. +- A pointer to one of the above types (**pointers to slices and slices of pointers are not supported**). ```go title="Example" type Person struct { - Name string `query:"name,default:john"` - Pass string `query:"pass"` - Products []string `query:"products,default:shoe|hat"` + Name string `query:"name,default=John"` + Pass string `query:"pass"` + Products []string `query:"products,default=shoe|hat"` } app.Get("/", func(c fiber.Ctx) error { @@ -600,13 +630,16 @@ app.Get("/", func(c fiber.Ctx) error { 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 +``` + +Run tests with the following `curl` command: -// curl "http://localhost:3000/?pass=doe" +```bash +curl "http://localhost:3000/?pass=doe" ``` diff --git a/docs/api/hooks.md b/docs/api/hooks.md index 828d68a359..4852866602 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 these hooks: +With Fiber you can execute custom user functions at specific method execution points. Here is a list of these hooks: - [OnRoute](#onroute) - [OnName](#onname) @@ -21,7 +21,7 @@ With Fiber v2.30.0, you can execute custom user functions when to run some metho ## Constants ```go -// Handlers define a function to create hooks for Fiber. +// Handlers define functions to create hooks for Fiber. type OnRouteHandler = func(Route) error type OnNameHandler = OnRouteHandler type OnGroupHandler = func(Group) error @@ -34,7 +34,7 @@ type OnMountHandler = func(*App) error ## OnRoute -OnRoute is a hook to execute user functions on each route registration. Also you can get route properties by **route** parameter. +`OnRoute` is a hook to execute user functions on each route registration. You can access route properties via the **route** parameter. ```go title="Signature" func (h *Hooks) OnRoute(handler ...OnRouteHandler) @@ -42,10 +42,10 @@ func (h *Hooks) OnRoute(handler ...OnRouteHandler) ## OnName -OnName is a hook to execute user functions on each route naming. Also you can get route properties by **route** parameter. +`OnName` is a hook to execute user functions on each route naming. You can access route properties via the **route** parameter. :::caution -OnName only works with naming routes, not groups. +`OnName` only works with named routes, not groups. ::: ```go title="Signature" @@ -73,13 +73,11 @@ func main() { app.Hooks().OnName(func(r fiber.Route) error { fmt.Print("Name: " + r.Name + ", ") - return nil }) app.Hooks().OnName(func(r fiber.Route) error { fmt.Print("Method: " + r.Method + "\n") - return nil }) @@ -104,7 +102,7 @@ func main() { ## OnGroup -OnGroup is a hook to execute user functions on each group registration. Also you can get group properties by **group** parameter. +`OnGroup` is a hook to execute user functions on each group registration. You can access group properties via the **group** parameter. ```go title="Signature" func (h *Hooks) OnGroup(handler ...OnGroupHandler) @@ -112,10 +110,10 @@ func (h *Hooks) OnGroup(handler ...OnGroupHandler) ## OnGroupName -OnGroupName is a hook to execute user functions on each group naming. Also you can get group properties by **group** parameter. +`OnGroupName` is a hook to execute user functions on each group naming. You can access group properties via the **group** parameter. :::caution -OnGroupName only works with naming groups, not routes. +`OnGroupName` only works with named groups, not routes. ::: ```go title="Signature" @@ -124,7 +122,7 @@ func (h *Hooks) OnGroupName(handler ...OnGroupNameHandler) ## OnListen -OnListen is a hook to execute user functions on Listen, ListenTLS, Listener. +`OnListen` is a hook to execute user functions on `Listen`, `ListenTLS`, and `Listener`. ```go title="Signature" func (h *Hooks) OnListen(handler ...OnListenHandler) @@ -134,23 +132,35 @@ func (h *Hooks) OnListen(handler ...OnListenHandler) ```go -app := fiber.New(fiber.Config{ - DisableStartupMessage: true, -}) - -app.Hooks().OnListen(func(listenData fiber.ListenData) error { - if fiber.IsChild() { - return nil - } - scheme := "http" - if data.TLS { - scheme = "https" - } - log.Println(scheme + "://" + listenData.Host + ":" + listenData.Port) - return nil -}) - -app.Listen(":5000") +package main + +import ( + "log" + "os" + + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/log" +) + +func main() { + app := fiber.New(fiber.Config{ + DisableStartupMessage: true, + }) + + app.Hooks().OnListen(func(listenData fiber.ListenData) error { + if fiber.IsChild() { + return nil + } + scheme := "http" + if listenData.TLS { + scheme = "https" + } + log.Println(scheme + "://" + listenData.Host + ":" + listenData.Port) + return nil + }) + + app.Listen(":5000") +} ``` @@ -158,7 +168,7 @@ app.Listen(":5000") ## OnFork -OnFork is a hook to execute user functions on Fork. +`OnFork` is a hook to execute user functions on fork. ```go title="Signature" func (h *Hooks) OnFork(handler ...OnForkHandler) @@ -166,7 +176,7 @@ func (h *Hooks) OnFork(handler ...OnForkHandler) ## OnShutdown -OnShutdown is a hook to execute user functions after Shutdown. +`OnShutdown` is a hook to execute user functions after shutdown. ```go title="Signature" func (h *Hooks) OnShutdown(handler ...OnShutdownHandler) @@ -174,10 +184,10 @@ func (h *Hooks) OnShutdown(handler ...OnShutdownHandler) ## OnMount -OnMount is a hook to execute user function after mounting process. The mount event is fired when sub-app is mounted on a parent app. The parent app is passed as a parameter. It works for app and group mounting. +`OnMount` is a hook to execute user functions after the mounting process. The mount event is fired when a sub-app is mounted on a parent app. The parent app is passed as a parameter. It works for both app and group mounting. ```go title="Signature" -func (h *Hooks) OnMount(handler ...OnMountHandler) +func (h *Hooks) OnMount(handler ...OnMountHandler) ``` @@ -193,24 +203,27 @@ import ( ) func main() { - app := New() + app := fiber.New() app.Get("/", testSimpleHandler).Name("x") - subApp := New() + subApp := fiber.New() subApp.Get("/test", testSimpleHandler) subApp.Hooks().OnMount(func(parent *fiber.App) error { - fmt.Print("Mount path of parent app: "+parent.MountPath()) - // ... - + fmt.Print("Mount path of parent app: " + parent.MountPath()) + // Additional custom logic... return nil }) app.Mount("/sub", subApp) } +func testSimpleHandler(c fiber.Ctx) error { + return c.SendString("Hello, Fiber!") +} + // Result: -// Mount path of parent app: +// Mount path of parent app: /sub ``` diff --git a/docs/api/log.md b/docs/api/log.md index 508be9a640..53f964a7dc 100644 --- a/docs/api/log.md +++ b/docs/api/log.md @@ -9,7 +9,7 @@ Logs serve as an essential tool for observing program behavior, diagnosing issue Fiber offers a default mechanism for logging to standard output. Additionally, it provides several global functions, including `log.Info`, `log.Errorf`, `log.Warnw`, among others, to facilitate comprehensive logging capabilities. -## Log levels +## Log Levels ```go const ( @@ -23,9 +23,9 @@ const ( ) ``` -## Custom log +## Custom Log -Fiber provides the `AllLogger` interface for adapting the various log libraries. +Fiber provides the `AllLogger` interface for adapting various log libraries. ```go type CommonLogger interface { @@ -41,13 +41,13 @@ type AllLogger interface { } ``` -## Print log +## Print Log -Note: The Fatal level method will terminate the program after printing the log message. Please use it with caution. +**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`. +Logs of different levels can be directly printed. These logs will be entered into `messageKey`, with the default key being `msg`. ```go log.Info("Hello, World!") @@ -55,7 +55,7 @@ log.Debug("Are you OK?") log.Info("42 is the answer to life, the universe, and everything") log.Warn("We are under attack!") log.Error("Houston, we have a problem.") -log.Fatal("So Long, and Thanks for All the Fislog.") +log.Fatal("So Long, and Thanks for All the Fish.") log.Panic("The system is down.") ``` @@ -65,10 +65,10 @@ Logs of different levels can be formatted before printing. All such methods end ```go log.Debugf("Hello %s", "boy") -log.Infof("%d is the answer to life, the universe, and everything", 233) -log.Warnf("We are under attack %s!", "boss") +log.Infof("%d is the answer to life, the universe, and everything", 42) +log.Warnf("We are under attack, %s!", "boss") log.Errorf("%s, we have a problem.", "Master Shifu") -log.Fatalf("So Long, and Thanks for All the %s.", "banana") +log.Fatalf("So Long, and Thanks for All the %s.", "fish") ``` ### Key-Value Logging @@ -76,14 +76,14 @@ log.Fatalf("So Long, and Thanks for All the %s.", "banana") Print a message with key-value pairs. If the key and value are not paired correctly, the log will output `KEYVALS UNPAIRED`. ```go -log.Debugw("", "Hello", "boy") -log.Infow("", "number", 233) +log.Debugw("", "greeting", "Hello", "target", "boy") +log.Infow("", "number", 42) log.Warnw("", "job", "boss") log.Errorw("", "name", "Master Shifu") -log.Fatalw("", "fruit", "banana") +log.Fatalw("", "fruit", "fish") ``` -## Global log +## Global Log For projects that require a simple, global logging function to print messages at any time, Fiber provides a global log. @@ -96,7 +96,7 @@ log.Warn("warn") These global log functions allow you to log messages conveniently throughout your project. -The above example uses the default `log.DefaultLogger` for standard output. You can also find various pre-implemented adapters under the [contrib](https://github.com/gofiber/contrib) package such as `fiberzap` and `fiberzerolog`, or you can implement your own logger and set it as the global logger using `log.SetLogger`.This flexibility allows you to tailor the logging behavior to suit your project's needs. +The above example uses the default `log.DefaultLogger` for standard output. You can also find various pre-implemented adapters under the [contrib](https://github.com/gofiber/contrib) package such as `fiberzap` and `fiberzerolog`, or you can implement your own logger and set it as the global logger using `log.SetLogger`. This flexibility allows you to tailor the logging behavior to suit your project's needs. Here's an example using a custom logger: @@ -106,22 +106,25 @@ import ( fiberlog "github.com/gofiber/fiber/v3/log" ) -var _ log.AllLogger = (*customLogger)(nil) +var _ fiberlog.AllLogger = (*customLogger)(nil) type customLogger struct { stdlog *log.Logger } -// ... -// inject your custom logger -fiberlog.SetLogger(customLogger) +// Implement required methods for the AllLogger interface... + +// Inject your custom logger +fiberlog.SetLogger(&customLogger{ + stdlog: log.New(os.Stdout, "CUSTOM ", log.LstdFlags), +}) ``` ## 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**. +**Note:** This method is not **concurrent-safe**. ```go import "github.com/gofiber/fiber/v3/log" @@ -131,14 +134,14 @@ log.SetLevel(log.LevelInfo) Setting the log level allows you to control the verbosity of the logs, filtering out messages below the specified level. -## Set output +## Set Output `log.SetOutput` sets the output destination of the logger. By default, the logger outputs logs to the console. -### Writing logs to stderr +### Writing Logs to Stderr ```go -var logger AllLogger = &defaultLogger{ +var logger fiberlog.AllLogger = &defaultLogger{ stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), depth: 4, } @@ -146,31 +149,34 @@ var logger AllLogger = &defaultLogger{ This allows you to customize where the logs are written, such as to a file, an external logging service, or any other desired destination. -### Writing logs to a file +### Writing Logs to a File -Set the output destination to the file, in this case `test.log`: +Set the output destination to a file, in this case `test.log`: ```go // Output to ./test.log file f, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { - return + log.Fatal("Failed to open log file:", err) } log.SetOutput(f) ``` -### Writing logs to both console and file +### Writing Logs to Both Console and File The following example will write the logs to both `test.log` and `stdout`: ```go // Output to ./test.log file -file, _ := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) +file, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) +if err != nil { + log.Fatal("Failed to open log file:", err) +} iw := io.MultiWriter(os.Stdout, file) log.SetOutput(iw) ``` -## Bind context +## Bind Context To bind a logger to a specific context, use the following method. This will return a `CommonLogger` instance that is bound to the specified context. diff --git a/docs/api/redirect.md b/docs/api/redirect.md index 79faa36d45..e353fc295b 100644 --- a/docs/api/redirect.md +++ b/docs/api/redirect.md @@ -6,14 +6,13 @@ sidebar_position: 5 toc_max_heading_level: 5 --- -Is used to redirect the ctx(request) to a different URL/Route. +The redirect package is used to redirect the context (request) to a different URL or route. ## Redirect Methods ### To -Redirects to the URL derived from the specified path, with specified [status](#status), a positive integer that -corresponds to an HTTP status code. +Redirects to the URL derived from the specified path, with a specified [status](#status), a positive integer that corresponds to an HTTP status code. :::info If **not** specified, status defaults to **302 Found**. @@ -49,10 +48,10 @@ app.Get("/", func(c fiber.Ctx) error { ### Route -Redirects to the specific route along with the parameters and queries. +Redirects to a specific route along with the parameters and queries. :::info -If you want to send queries and params to route, you must use the [**RedirectConfig**](#redirectconfig) struct. +If you want to send queries and params to a route, you must use the [**RedirectConfig**](#redirectconfig) struct. ::: ```go title="Signature" @@ -71,7 +70,7 @@ app.Get("/", func(c fiber.Ctx) error { app.Get("/with-queries", func(c fiber.Ctx) error { // /user/fiber?data[0][name]=john&data[0][age]=10&test=doe - return c.Route("user", RedirectConfig{ + return c.Redirect().Route("user", fiber.RedirectConfig{ Params: fiber.Map{ "name": "fiber", }, @@ -90,8 +89,7 @@ app.Get("/user/:name", func(c fiber.Ctx) error { ### Back -Redirects back to refer URL. It redirects to fallback URL if refer header doesn't exists, with specified status, a -positive integer that corresponds to an HTTP status code. +Redirects back to the referer URL. It redirects to a fallback URL if the referer header doesn't exist, with a specified status, a positive integer that corresponds to an HTTP status code. :::info If **not** specified, status defaults to **302 Found**. @@ -105,6 +103,7 @@ func (r *Redirect) Back(fallback string) error app.Get("/", func(c fiber.Ctx) error { return c.SendString("Home page") }) + app.Get("/test", func(c fiber.Ctx) error { c.Set("Content-Type", "text/html") return c.SendString(`Back`) @@ -118,7 +117,7 @@ app.Get("/back", func(c fiber.Ctx) error { ## Controls :::info -Method are **chainable**. +Methods are **chainable**. ::: ### Status @@ -126,7 +125,7 @@ Method are **chainable**. Sets the HTTP status code for the redirect. :::info -Is used in conjunction with [**To**](#to), [**Route**](#route) and [**Back**](#back) methods. +It is used in conjunction with [**To**](#to), [**Route**](#route), and [**Back**](#back) methods. ::: ```go title="Signature" @@ -145,11 +144,11 @@ app.Get("/coffee", func(c fiber.Ctx) error { Sets the configuration for the redirect. :::info -Is used in conjunction with the [**Route**](#route) method. +It is used in conjunction with the [**Route**](#route) method. ::: -```go -// RedirectConfig A config to use with Redirect().Route() +```go title="Definition" +// RedirectConfig is a config to use with Redirect().Route() type RedirectConfig struct { Params fiber.Map // Route parameters Queries map[string]string // Query map @@ -158,7 +157,7 @@ type RedirectConfig struct { ### Flash Message -Similar to [Laravel](https://laravel.com/docs/11.x/redirects#redirecting-with-flashed-session-data) we can flash a message and retrieve it in the next request. +Similar to [Laravel](https://laravel.com/docs/11.x/redirects#redirecting-with-flashed-session-data), we can flash a message and retrieve it in the next request. #### Messages @@ -177,7 +176,7 @@ app.Get("/", func(c fiber.Ctx) error { #### Message -Get flash message by key. Check [With](#with) for more information. +Get a flash message by key. Check [With](#with) for more information. ```go title="Signature" func (r *Redirect) Message(key string) *Redirect @@ -241,10 +240,9 @@ app.Get("/", func(c fiber.Ctx) error { #### WithInput -You can send input data by using `WithInput()`. -They will be sent as a cookie. +You can send input data by using `WithInput()`. They will be sent as a cookie. -This method can send form, multipart form, query data to redirected route depending on the request content type. +This method can send form, multipart form, or query data to the redirected route depending on the request content type. ```go title="Signature" func (r *Redirect) WithInput() *Redirect From 5aae1c9d9ad22212c93c83e9b41a5286ba0eafed Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:44:25 -0500 Subject: [PATCH 2/6] Update .github/README.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/README.md b/.github/README.md index d3eca5b610..5920447444 100644 --- a/.github/README.md +++ b/.github/README.md @@ -645,10 +645,11 @@ import ( func main() { app := fiber.New(fiber.Config{ - // Trust all proxies (use with caution) + // Configure trusted proxies - WARNING: Only trust proxies you control + // Using TrustProxy: true with unrestricted IPs can lead to IP spoofing TrustProxy: true, TrustProxyConfig: fiber.TrustProxyConfig{ - Proxies: []string{"0.0.0.0", "1.1.1.1/30"}, // IP address or IP address range + Proxies: []string{"10.0.0.0/8", "172.16.0.0/12"}, // Example: Internal network ranges only }, ProxyHeader: fiber.HeaderXForwardedFor, }) From d571061c331f4b5312b42e6bb609bd10ace2820e Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:56:29 -0500 Subject: [PATCH 3/6] Remove trailing spaces --- docs/api/app.md | 8 ++++---- docs/api/bind.md | 7 ------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/docs/api/app.md b/docs/api/app.md index 8223398887..403213d3b0 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -50,7 +50,7 @@ The `MountPath` property contains one or more path patterns on which a sub-app w ```go title="Signature" func (app *App) MountPath() string ``` - + ```go title="Example" package main @@ -89,7 +89,7 @@ You can group routes by creating a `*Group` struct. ```go title="Signature" func (app *App) Group(prefix string, handlers ...Handler) Router ``` - + ```go title="Example" package main @@ -622,7 +622,7 @@ func main() { ## RegisterCustomConstraint `RegisterCustomConstraint` allows you to register custom constraints. - + ```go title="Signature" func (app *App) RegisterCustomConstraint(constraint CustomConstraint) ``` @@ -632,7 +632,7 @@ See the [Custom Constraint](../guide/routing.md#custom-constraint) section for m ## SetTLSHandler Use `SetTLSHandler` to set [`ClientHelloInfo`](https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2) when using TLS with a `Listener`. - + ```go title="Signature" func (app *App) SetTLSHandler(tlsHandler *TLSHandler) ``` diff --git a/docs/api/bind.md b/docs/api/bind.md index d72a9009c7..6a5f6dd30a 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -464,13 +464,6 @@ If there's an error, it will return the error and set HTTP status to `400 Bad Re func (b *Bind) Must() *Bind ``` -```go title="Example" -app.Get("/coffee", func(c fiber.Ctx) error { - // => HTTP - GET 301 /teapot - return c.Redirect().Status(fiber.StatusMovedPermanently).To("/teapot") -}) -``` - ### Should To handle binder errors manually, you can use the `Should` method. From 1ef62565a323c9162a18c0d878232f00cf185d26 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Fri, 15 Nov 2024 23:17:06 -0500 Subject: [PATCH 4/6] Updates based on PR comments --- .github/README.md | 4 ++-- docs/api/app.md | 12 +++++++----- docs/api/bind.md | 9 ++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/README.md b/.github/README.md index 5920447444..aa58a8d83c 100644 --- a/.github/README.md +++ b/.github/README.md @@ -704,8 +704,8 @@ Here is a list of middleware that are included within the Fiber framework. List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Description | -|-------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------| +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | | [contrib](https://github.com/gofiber/contrib) | Third-party middlewares | | [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | | [template](https://github.com/gofiber/template) | This package contains 9 template engines that can be used with Fiber `v3`. Go version 1.22 or higher is required. | diff --git a/docs/api/app.md b/docs/api/app.md index 403213d3b0..8c7f8979bc 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -225,13 +225,15 @@ import ( "github.com/gofiber/fiber/v3" ) +var handler = func(c fiber.Ctx) error { return nil } + func main() { app := fiber.New() app.Get("/john/:age", handler) app.Post("/register", handler) - data, _err_ := json.MarshalIndent(app.Stack(), "", " ") + data, _ := json.MarshalIndent(app.Stack(), "", " ") fmt.Println(string(data)) log.Fatal(app.Listen(":3000")) @@ -496,7 +498,7 @@ func (app *App) Config() Config ## Handler -`Handler` returns the server handler that can be used to serve custom [`*fasthttp.RequestCtx`](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) requests. +`Handler` returns the server handler that can be used to serve custom [`\*fasthttp.RequestCtx`](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) requests. ```go title="Signature" func (app *App) Handler() fasthttp.RequestHandler @@ -578,15 +580,15 @@ type User struct { type customBinder struct{} -func (cb *customBinder) Name() string { +func (*customBinder) Name() string { return "custom" } -func (cb *customBinder) MIMETypes() []string { +func (*customBinder) MIMETypes() []string { return []string{"application/yaml"} } -func (cb *customBinder) Parse(c fiber.Ctx, out any) error { +func (*customBinder) Parse(c fiber.Ctx, out any) error { // Parse YAML body return yaml.Unmarshal(c.Body(), out) } diff --git a/docs/api/bind.md b/docs/api/bind.md index 6a5f6dd30a..16ca01b6f1 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -163,6 +163,7 @@ func (b *Bind) MultipartForm(out any) error ``` ```go title="Example" +// Field names should start with an uppercase letter type Person struct { Name string `form:"name"` Pass string `form:"pass"` @@ -199,6 +200,7 @@ func (b *Bind) XML(out any) error ``` ```go title="Example" +// Field names should start with an uppercase letter type Person struct { Name string `xml:"name"` Pass string `xml:"pass"` @@ -438,6 +440,7 @@ type User struct { Name string `yaml:"name"` } +// curl -X POST http://localhost:3000/custom -H "Content-Type: application/yaml" -d "name: John" app.Post("/custom", func(c fiber.Ctx) error { var user User // Use Custom binder by name @@ -611,9 +614,9 @@ You can set default values for fields in the struct by using the `default` struc ```go title="Example" type Person struct { - Name string `query:"name,default=John"` - Pass string `query:"pass"` - Products []string `query:"products,default=shoe|hat"` + Name string `query:"name,default:john"` + Pass string `query:"pass"` + Products []string `query:"products,default:shoe|hat"` } app.Get("/", func(c fiber.Ctx) error { From cba6b582038f9d6b39cdd3a8d4ebe3b8d9b2874b Mon Sep 17 00:00:00 2001 From: RW Date: Sat, 16 Nov 2024 15:20:45 +0100 Subject: [PATCH 5/6] Update docs/api/bind.md --- docs/api/bind.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/bind.md b/docs/api/bind.md index 16ca01b6f1..2ad0854ca9 100644 --- a/docs/api/bind.md +++ b/docs/api/bind.md @@ -626,7 +626,7 @@ app.Get("/", func(c fiber.Ctx) error { return err } - log.Println(p.Name) // John + log.Println(p.Name) // john log.Println(p.Pass) // doe log.Println(p.Products) // ["shoe", "hat"] From a6d50761d9443624276a3300c8a57638b4a30a3d Mon Sep 17 00:00:00 2001 From: RW Date: Sat, 16 Nov 2024 15:22:46 +0100 Subject: [PATCH 6/6] Update docs/api/redirect.md --- docs/api/redirect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/redirect.md b/docs/api/redirect.md index e353fc295b..fa8bd1b3cc 100644 --- a/docs/api/redirect.md +++ b/docs/api/redirect.md @@ -6,7 +6,7 @@ sidebar_position: 5 toc_max_heading_level: 5 --- -The redirect package is used to redirect the context (request) to a different URL or route. +The redirect methods are used to redirect the context (request) to a different URL or route. ## Redirect Methods