fiber/docs/whats_new.md

20 KiB
Raw Blame History

id title sidebar_position toc_max_heading_level
whats_new 🆕 Whats New in v3 2 3

:::caution

It's a draft, not finished yet.

:::

🎉 Welcome

We are excited to announce the release of Fiber v3! 🚀

In this guide, we'll walk you through the most important changes in Fiber v3 and show you how to migrate your existing Fiber v2 applications to Fiber v3.

Here's a quick overview of the changes in Fiber v3:

Drop for old Go versions

Fiber v3 drops support for Go versions below 1.21. We recommend upgrading to Go 1.21 or higher to use Fiber v3.

🚀 App

:::caution DRAFT section :::

We have made several changes to the Fiber app, including:

  • Listen -> unified with config
  • Static -> has been removed and moved to static middleware
  • app.Config properties moved to listen config
    • DisableStartupMessage
    • EnablePrefork -> previously Prefork
    • EnablePrintRoutes
    • ListenerNetwork -> previously Network

new methods

  • RegisterCustomBinder
  • RegisterCustomConstraint
  • NewCtxFunc

removed methods

  • Mount -> Use app.Use() instead
  • ListenTLS -> Use app.Listen() with tls.Config
  • ListenTLSWithCertificate -> Use app.Listen() with tls.Config
  • ListenMutualTLS -> Use app.Listen() with tls.Config
  • ListenMutualTLSWithCertificate -> Use app.Listen() with tls.Config

Methods changes

  • Test -> timeout changed to 1 second
  • Listen -> has a config parameter
  • Listener -> has a config parameter

CTX interface + customizable


🗺 Router

We have slightly adapted our router interface

HTTP method registration

In v2 one handler was already mandatory when the route has been registered, but this was checked at runtime and was not correctly reflected in the signature, this has now been changed in v3 to make it more explicit.

-    Get(path string, handlers ...Handler) Router
+    Get(path string, handler Handler, middleware ...Handler) Router
-    Head(path string, handlers ...Handler) Router
+    Head(path string, handler Handler, middleware ...Handler) Router
-    Post(path string, handlers ...Handler) Router
+    Post(path string, handler Handler, middleware ...Handler) Router
-    Put(path string, handlers ...Handler) Router
+    Put(path string, handler Handler, middleware ...Handler) Router
-    Delete(path string, handlers ...Handler) Router
+    Delete(path string, handler Handler, middleware ...Handler) Router
-    Connect(path string, handlers ...Handler) Router
+    Connect(path string, handler Handler, middleware ...Handler) Router
-    Options(path string, handlers ...Handler) Router
+    Options(path string, handler Handler, middleware ...Handler) Router
-    Trace(path string, handlers ...Handler) Router
+    Trace(path string, handler Handler, middleware ...Handler) Router
-    Patch(path string, handlers ...Handler) Router
+    Patch(path string, handler Handler, middleware ...Handler) Router
-    All(path string, handlers ...Handler) Router
+    All(path string, handler Handler, middleware ...Handler) Router

Route chaining

The route method is now like Express which gives you the option of a different notation and allows you to concatenate the route declaration.

-    Route(prefix string, fn func(router Router), name ...string) Router
+    Route(path string) Register    
Example
app.Route("/api").Route("/user/:id?")
    .Get(func(c fiber.Ctx) error {
        // Get user
        return c.JSON(fiber.Map{"message": "Get user", "id": c.Params("id")})
    })
    .Post(func(c fiber.Ctx) error {
        // Create user
        return c.JSON(fiber.Map{"message": "User created"})
    })
    .Put(func(c fiber.Ctx) error {
        // Update user
        return c.JSON(fiber.Map{"message": "User updated", "id": c.Params("id")})
    })
    .Delete(func(c fiber.Ctx) error {
        // Delete user
        return c.JSON(fiber.Map{"message": "User deleted", "id": c.Params("id")})
    })
})

Here you can find more information.

Middleware registration

We have aligned our method for middlewares closer to Express and now also support the Use of multiple prefixes.

Registering a subapp is now also possible via the Use method instead of the old app.Mount method.

Example
// register mulitple prefixes
app.Use(["/v1", "/v2"], func(c *fiber.Ctx) error {
    // Middleware for /v1 and /v2
    return c.Next() 
})

// define subapp
api := fiber.New()
api.Get("/user", func(c *fiber.Ctx) error {
    return c.SendString("User")
})
// register subapp
app.Use("/api", api)

To enable the routing changes above we had to slightly adjust the signature of the Add method.

-    Add(method, path string, handlers ...Handler) Router
+    Add(methods []string, path string, handler Handler, middleware ...Handler) Router

🧠 Context

:::caution DRAFT section :::

New Features

  • Cookie now allows Partitioned cookies for CHIPS support. CHIPS (Cookies Having Independent Partitioned State) is a feature that improves privacy by allowing cookies to be partitioned by top-level site, mitigating cross-site tracking.

new methods

  • AutoFormat -> ExpressJs like
  • Host -> ExpressJs like
  • Port -> ExpressJs like
  • IsProxyTrusted
  • Reset
  • Schema -> ExpressJs like
  • SendStream -> ExpressJs like
  • SendString -> ExpressJs like
  • String -> ExpressJs like
  • ViewBind -> instead of Bind

removed methods

  • AllParams -> c.Bind().URL() ?
  • ParamsInt -> Params Generic
  • QueryBool -> Query Generic
  • QueryFloat -> Query Generic
  • QueryInt -> Query Generic
  • BodyParser -> c.Bind().Body()
  • CookieParser -> c.Bind().Cookie()
  • ParamsParser -> c.Bind().URL()
  • RedirectToRoute -> c.Redirect().Route()
  • RedirectBack -> c.Redirect().Back()
  • ReqHeaderParser -> c.Bind().Header()

changed methods

  • Bind -> for Binding instead of View, us c.ViewBind()
  • Format -> Param: body interface{} -> handlers ...ResFmt
  • Redirect -> c.Redirect().To()
  • SendFile now supports different configurations using the config parameter.

🌎 Client package

The Gofiber client has been completely rebuilt. It includes numerous new features such as Cookiejar, request/response hooks, and more. You can take a look to client docs to see what's new with the client.

📎 Binding

:::caution DRAFT section :::

🔄 Redirect

We are excited to introduce enhancements to the Redirect feature in this major release! These improvements enhance your ability to manage user navigation efficiently and effectively.

The Redirect feature allows you to seamlessly redirect users to different URLs or routes within your application. It supports various use cases such as redirecting after form submissions, handling outdated links, and creating more intuitive navigation flows.

Key Features

  1. Flash Messages: Send and retrieve flash messages with ease. Use With(key, value) to send flash messages, and access them in the next request using Messages() or Message(key).

  2. Old Input Data: Preserve and retrieve old input data across requests. Use WithInput() to store form data, which can then be accessed using OldInputs() or OldInput(key).

  3. Customizable HTTP Status Codes: Set specific HTTP status codes for your redirects using the Status(code) method, with a default of 302 Found.

Backend

The Redirect feature leverages cookies to store flash messages and old input data, ensuring data persistence across redirects and making it easy to manage user data and messages. The cookies are fully configurable on a per-route basis using the CookieConfig param in the RedirectConfig struct.

🧰 Generic functions

:::caution DRAFT section :::

🧬 Middlewares

Adaptor

The adaptor middleware has been significantly optimized for performance and efficiency. Key improvements include reduced response times, lower memory usage, and fewer memory allocations. These changes make the middleware more reliable and capable of handling higher loads effectively. Enhancements include the introduction of a sync.Pool for managing fasthttp.RequestCtx instances and better HTTP request and response handling between net/http and fasthttp contexts.

Payload Size Metric V2 V3 Percent Change
100KB Execution Time 1056 ns/op 588.6 ns/op -44.25%
Memory Usage 2644 B/op 254 B/op -90.39%
Allocations 16 allocs/op 5 allocs/op -68.75%
500KB Execution Time 1061 ns/op 562.9 ns/op -46.94%
Memory Usage 2644 B/op 248 B/op -90.62%
Allocations 16 allocs/op 5 allocs/op -68.75%
1MB Execution Time 1080 ns/op 629.7 ns/op -41.68%
Memory Usage 2646 B/op 267 B/op -89.91%
Allocations 16 allocs/op 5 allocs/op -68.75%
5MB Execution Time 1093 ns/op 540.3 ns/op -50.58%
Memory Usage 2654 B/op 254 B/op -90.43%
Allocations 16 allocs/op 5 allocs/op -68.75%
10MB Execution Time 1044 ns/op 533.1 ns/op -48.94%
Memory Usage 2665 B/op 258 B/op -90.32%
Allocations 16 allocs/op 5 allocs/op -68.75%
25MB Execution Time 1069 ns/op 540.7 ns/op -49.42%
Memory Usage 2706 B/op 289 B/op -89.32%
Allocations 16 allocs/op 5 allocs/op -68.75%
50MB Execution Time 1137 ns/op 554.6 ns/op -51.21%
Memory Usage 2734 B/op 298 B/op -89.10%
Allocations 16 allocs/op 5 allocs/op -68.75%

Cache

We are excited to introduce a new option in our caching middleware: Cache Invalidator. This feature provides greater control over cache management, allowing you to define a custom conditions for invalidating cache entries.

CORS

We've made some changes to the CORS middleware to improve its functionality and flexibility. Here's what's new:

New Struct Fields

  • Config.AllowPrivateNetwork: This new field is a boolean that allows you to control whether private networks are allowed. This is related to the Private Network Access (PNA) specification from the Web Incubator Community Group (WICG). When set to true, the CORS middleware will allow CORS preflight requests from private networks and respond with the Access-Control-Allow-Private-Network: true header. This could be useful in development environments or specific use cases, but should be done with caution due to potential security risks.

Updated Struct Fields

We've updated several fields from a single string (containing comma-separated values) to slices, allowing for more explicit declaration of multiple values. Here are the updated fields:

  • Config.AllowOrigins: Now accepts a slice of strings, each representing an allowed origin.
  • Config.AllowMethods: Now accepts a slice of strings, each representing an allowed method.
  • Config.AllowHeaders: Now accepts a slice of strings, each representing an allowed header.
  • Config.ExposeHeaders: Now accepts a slice of strings, each representing an exposed header.

Compression

We've added support for zstd compression on top of gzip, deflate, and brotli.

EncryptCookie

Added support for specifying Key length when using encryptcookie.GenerateKey(length). This allows the user to generate keys compatible with AES-128, AES-192, and AES-256 (Default).

Session

:::caution DRAFT section :::

Filesystem

We've decided to remove filesystem middleware to clear up the confusion between static and filesystem middleware. Now, static middleware can do everything that filesystem middleware and static do. You can check out static middleware or migration guide to see what has been changed.

Monitor

:::caution DRAFT section :::

Monitor middleware is now in Contrib package.

Healthcheck

The Healthcheck middleware has been enhanced to support more than two routes, with default endpoints for liveliness, readiness, and startup checks. Here's a detailed breakdown of the changes and how to use the new features.

  1. Support for More Than Two Routes:

    • The updated middleware now supports multiple routes beyond the default liveliness and readiness endpoints. This allows for more granular health checks, such as startup probes.
  2. Default Endpoints:

    • Three default endpoints are now available:
      • Liveness: /livez
      • Readiness: /readyz
      • Startup: /startupz
    • These endpoints can be customized or replaced with user-defined routes.
  3. Simplified Configuration:

    • The configuration for each health check endpoint has been simplified. Each endpoint can be configured separately, allowing for more flexibility and readability.

Refer to the healthcheck middleware migration guide or the general migration guide to review the changes.

📋 Migration guide

🚀 App

Static

Since we've removed app.Static(), you need to move methods to static middleware like the example below:

// Before
app.Static("/", "./public")
app.Static("/prefix", "./public")
app.Static("/prefix", "./public", Static{
    Index: "index.htm",
})
app.Static("*", "./public/index.html")
// After
app.Get("/*", static.New("./public"))
app.Get("/prefix*", static.New("./public"))
app.Get("/prefix*", static.New("./public", static.Config{
    IndexNames: []string{"index.htm", "index.html"},
}))
app.Get("*", static.New("./public/index.html"))

:::caution You have to put * to the end of the route if you don't define static route with app.Use. :::

🗺 Router

The signatures for Add and Route have been changed.

To migrate Add you must change the methods in a slice.

// Before
app.Add(fiber.MethodPost, "/api", myHandler)
// After
app.Add([]string{fiber.MethodPost}, "/api", myHandler)

To migrate Route you need to read this.

// Before
app.Route("/api", func(apiGrp Router) {
    apiGrp.Route("/user/:id?", func(userGrp Router) {
        userGrp.Get("/", func(c fiber.Ctx) error {
            // Get user
            return c.JSON(fiber.Map{"message": "Get user", "id": c.Params("id")})
        })
        userGrp.Post("/", func(c fiber.Ctx) error {
            // Create user
            return c.JSON(fiber.Map{"message": "User created"})
        })
    })
})
// After
app.Route("/api").Route("/user/:id?")
    .Get(func(c fiber.Ctx) error {
        // Get user
        return c.JSON(fiber.Map{"message": "Get user", "id": c.Params("id")})
    })
    .Post(func(c fiber.Ctx) error {
        // Create user
        return c.JSON(fiber.Map{"message": "User created"})
    });

🗺 RebuildTree

We have added a new method that allows the route tree stack to be rebuilt in runtime, with it, you can add a route while your application is running and rebuild the route tree stack to make it registered and available for calls.

You can find more reference on it in the app:

Example Usage

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)
    })

    app.RebuildTree()  // Rebuild the route tree to register the new route

    return c.SendStatus(http.StatusOK)
})

In this example, a new route is defined and then RebuildTree() is called to make sure the new route is registered and available.

Note: Use this method with caution. It is not thread-safe and calling it can be very performance-intensive, so it should be used sparingly and only in development mode. Avoid using it concurrently.

🧠 Context

📎 Parser

🔄 Redirect

🌎 Client package

🧬 Middlewares

CORS

The CORS middleware has been updated to use slices instead of strings for the AllowOrigins, AllowMethods, AllowHeaders, and ExposeHeaders fields. Here's how you can update your code:

// Before
app.Use(cors.New(cors.Config{
    AllowOrigins: "https://example.com,https://example2.com",
    AllowMethods: strings.Join([]string{fiber.MethodGet, fiber.MethodPost}, ","),
    AllowHeaders: "Content-Type",
    ExposeHeaders: "Content-Length",
}))

// After
app.Use(cors.New(cors.Config{
    AllowOrigins: []string{"https://example.com", "https://example2.com"},
    AllowMethods: []string{fiber.MethodGet, fiber.MethodPost},
    AllowHeaders: []string{"Content-Type"},
    ExposeHeaders: []string{"Content-Length"},
}))

Filesystem

You need to move filesystem middleware to static middleware due to it has been removed from the core.

// Before
app.Use(filesystem.New(filesystem.Config{
    Root: http.Dir("./assets"),
}))

app.Use(filesystem.New(filesystem.Config{
    Root:         http.Dir("./assets"),
    Browse:       true,
    Index:        "index.html",
    MaxAge:       3600,
}))
// After
app.Use(static.New("", static.Config{
    FS: os.DirFS("./assets"),
}))

app.Use(static.New("", static.Config{
    FS:           os.DirFS("./assets"),
    Browse:       true,
    IndexNames:   []string{"index.html"},
    MaxAge:       3600,
}))

Healthcheck

Previously, the Healthcheck middleware was configured with a combined setup for liveliness and readiness probes:

//before
app.Use(healthcheck.New(healthcheck.Config{
  LivenessProbe: func(c *fiber.Ctx) bool {
    return true
  },
  LivenessEndpoint: "/live",
  ReadinessProbe: func(c *fiber.Ctx) bool {
    return serviceA.Ready() && serviceB.Ready() && ...
  },
  ReadinessEndpoint: "/ready",
}))

With the new version, each health check endpoint is configured separately, allowing for more flexibility:

// after

// Default liveness endpoint configuration
app.Get(healthcheck.DefaultLivenessEndpoint, healthcheck.NewHealthChecker(healthcheck.Config{
  Probe: func(c *fiber.Ctx) bool {
    return true
  },
}))

// Default readiness endpoint configuration
app.Get(healthcheck.DefaultReadinessEndpoint, healthcheck.NewHealthChecker())

// New default startup endpoint configuration
// Default endpoint is /startupz
app.Get(healthcheck.DefaultStartupEndpoint, healthcheck.NewHealthChecker(healthcheck.Config{
  Probe: func(c *fiber.Ctx) bool {
    return serviceA.Ready() && serviceB.Ready() && ...
  },
}))

// Custom liveness endpoint configuration
app.Get("/live", healthcheck.NewHealthChecker())