1
0
Fork 0

Adding upstream version 2.52.6.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-17 06:50:16 +02:00
parent a960158181
commit 6d002e9543
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
441 changed files with 95392 additions and 0 deletions

View file

@ -0,0 +1,8 @@
{
"label": "Guide",
"position": 3,
"link": {
"type": "generated-index",
"description": "Guides for Fiber."
}
}

View file

@ -0,0 +1,128 @@
---
id: error-handling
title: 🐛 Error Handling
description: >-
Fiber supports centralized error handling by returning an error to the handler
which allows you to log errors to external services or send a customized HTTP
response to the client.
sidebar_position: 4
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Catching Errors
Its essential to ensure that Fiber catches all errors that occur while running route handlers and middleware. You must return them to the handler function, where Fiber will catch and process them.
<Tabs>
<TabItem value="example" label="Example">
```go
app.Get("/", func(c *fiber.Ctx) error {
// Pass error to Fiber
return c.SendFile("file-does-not-exist")
})
```
</TabItem>
</Tabs>
Fiber does not handle [panics](https://go.dev/blog/defer-panic-and-recover) by default. To recover from a panic thrown by any handler in the stack, you need to include the `Recover` middleware below:
```go title="Example"
package main
import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/recover"
)
func main() {
app := fiber.New()
app.Use(recover.New())
app.Get("/", func(c *fiber.Ctx) error {
panic("This panic is caught by fiber")
})
log.Fatal(app.Listen(":3000"))
}
```
You could use Fiber's custom error struct to pass an additional `status code` using `fiber.NewError()`. It's optional to pass a message; if this is left empty, it will default to the status code message \(`404` equals `Not Found`\).
```go title="Example"
app.Get("/", func(c *fiber.Ctx) error {
// 503 Service Unavailable
return fiber.ErrServiceUnavailable
// 503 On vacation!
return fiber.NewError(fiber.StatusServiceUnavailable, "On vacation!")
})
```
## Default Error Handler
Fiber provides an error handler by default. For a standard error, the response is sent as **500 Internal Server Error**. If the error is of type [fiber.Error](https://godoc.org/github.com/gofiber/fiber#Error), the response is sent with the provided status code and message.
```go title="Example"
// Default error handler
var DefaultErrorHandler = func(c *fiber.Ctx, err error) error {
// Status code defaults to 500
code := fiber.StatusInternalServerError
// Retrieve the custom status code if it's a *fiber.Error
var e *fiber.Error
if errors.As(err, &e) {
code = e.Code
}
// Set Content-Type: text/plain; charset=utf-8
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
// Return status code with error message
return c.Status(code).SendString(err.Error())
}
```
## Custom Error Handler
A custom error handler can be set using a [Config ](../api/fiber.md#config)when initializing a [Fiber instance](../api/fiber.md#new).
In most cases, the default error handler should be sufficient. However, a custom error handler can come in handy if you want to capture different types of errors and take action accordingly e.g., send a notification email or log an error to the centralized system. You can also send customized responses to the client e.g., error page or just a JSON response.
The following example shows how to display error pages for different types of errors.
```go title="Example"
// Create a new fiber instance with custom config
app := fiber.New(fiber.Config{
// Override default error handler
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
// Status code defaults to 500
code := fiber.StatusInternalServerError
// Retrieve the custom status code if it's a *fiber.Error
var e *fiber.Error
if errors.As(err, &e) {
code = e.Code
}
// Send custom error page
err = ctx.Status(code).SendFile(fmt.Sprintf("./%d.html", code))
if err != nil {
// In case the SendFile fails
return ctx.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
}
// Return from handler
return nil
},
})
// ...
```
> Special thanks to the [Echo](https://echo.labstack.com/) & [Express](https://expressjs.com/) framework for inspiration regarding error handling.

View file

@ -0,0 +1,36 @@
---
id: faster-fiber
title: ⚡ Make Fiber Faster
sidebar_position: 7
---
## Custom JSON Encoder/Decoder
Since Fiber v2.32.0, we use **encoding/json** as default json library due to stability and producibility. However, the standard library is a bit slow compared to 3rd party libraries. If you're not happy with the performance of **encoding/json**, we recommend you to use these libraries:
- [goccy/go-json](https://github.com/goccy/go-json)
- [bytedance/sonic](https://github.com/bytedance/sonic)
- [segmentio/encoding](https://github.com/segmentio/encoding)
- [mailru/easyjson](https://github.com/mailru/easyjson)
- [minio/simdjson-go](https://github.com/minio/simdjson-go)
- [wI2L/jettison](https://github.com/wI2L/jettison)
```go title="Example"
package main
import "github.com/gofiber/fiber/v2"
import "github.com/goccy/go-json"
func main() {
app := fiber.New(fiber.Config{
JSONEncoder: json.Marshal,
JSONDecoder: json.Unmarshal,
})
# ...
}
```
### References
- [Set custom JSON encoder for client](../api/client.md#jsonencoder)
- [Set custom JSON decoder for client](../api/client.md#jsondecoder)
- [Set custom JSON encoder for application](../api/fiber.md#config)
- [Set custom JSON decoder for application](../api/fiber.md#config)

79
docs/guide/grouping.md Normal file
View file

@ -0,0 +1,79 @@
---
id: grouping
title: 🎭 Grouping
sidebar_position: 2
---
:::info
In general, the Group functionality in Fiber behaves similarly to ExpressJS. Groups are declared virtually and all routes declared within the group are flattened into a single list with a prefix, which is then checked by the framework in the order it was declared. This means that the behavior of Group in Fiber is identical to that of ExpressJS.
:::
## Paths
Like **Routing**, groups can also have paths that belong to a cluster.
```go
func main() {
app := fiber.New()
api := app.Group("/api", middleware) // /api
v1 := api.Group("/v1", middleware) // /api/v1
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2", middleware) // /api/v2
v2.Get("/list", handler) // /api/v2/list
v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000"))
}
```
A **Group** of paths can have an optional handler.
```go
func main() {
app := fiber.New()
api := app.Group("/api") // /api
v1 := api.Group("/v1") // /api/v1
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2") // /api/v2
v2.Get("/list", handler) // /api/v2/list
v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000"))
}
```
:::caution
Running **/api**, **/v1** or **/v2** will result in **404** error, make sure you have the errors set.
:::
## Group Handlers
Group handlers can also be used as a routing path but they must have **Next** added to them so that the flow can continue.
```go
func main() {
app := fiber.New()
handler := func(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
}
api := app.Group("/api") // /api
v1 := api.Group("/v1", func(c *fiber.Ctx) error { // middleware for /api/v1
c.Set("Version", "v1")
return c.Next()
})
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
log.Fatal(app.Listen(":3000"))
}
```

218
docs/guide/hooks.md Normal file
View file

@ -0,0 +1,218 @@
---
id: hooks
title: 🎣 Hooks
sidebar_position: 6
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
With Fiber v2.30.0, you can execute custom user functions when to run some methods. Here is a list of this hooks:
- [OnRoute](#onroute)
- [OnName](#onname)
- [OnGroup](#ongroup)
- [OnGroupName](#ongroupname)
- [OnListen](#onlisten)
- [OnFork](#onfork)
- [OnShutdown](#onshutdown)
- [OnMount](#onmount)
## Constants
```go
// Handlers define a function to create hooks for Fiber.
type OnRouteHandler = func(Route) error
type OnNameHandler = OnRouteHandler
type OnGroupHandler = func(Group) error
type OnGroupNameHandler = OnGroupHandler
type OnListenHandler = func(ListenData) error
type OnForkHandler = func(int) error
type OnShutdownHandler = func() error
type OnMountHandler = func(*App) error
```
## OnRoute
OnRoute is a hook to execute user functions on each route registeration. Also you can get route properties by **route** parameter.
```go title="Signature"
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.
:::caution
OnName only works with naming routes, not groups.
:::
```go title="Signature"
func (h *Hooks) OnName(handler ...OnNameHandler)
```
<Tabs>
<TabItem value="onname-example" label="OnName Example">
```go
package main
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString(c.Route().Name)
}).Name("index")
app.Hooks().OnName(func(r fiber.Route) error {
fmt.Print("Name: " + r.Name + ", ")
return nil
})
app.Hooks().OnName(func(r fiber.Route) error {
fmt.Print("Method: " + r.Method + "\n")
return nil
})
app.Get("/add/user", func(c *fiber.Ctx) error {
return c.SendString(c.Route().Name)
}).Name("addUser")
app.Delete("/destroy/user", func(c *fiber.Ctx) error {
return c.SendString(c.Route().Name)
}).Name("destroyUser")
app.Listen(":5000")
}
// Results:
// Name: addUser, Method: GET
// Name: destroyUser, Method: DELETE
```
</TabItem>
</Tabs>
## OnGroup
OnGroup is a hook to execute user functions on each group registeration. Also you can get group properties by **group** parameter.
```go title="Signature"
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.
:::caution
OnGroupName only works with naming groups, not routes.
:::
```go title="Signature"
func (h *Hooks) OnGroupName(handler ...OnGroupNameHandler)
```
## OnListen
OnListen is a hook to execute user functions on Listen, ListenTLS, Listener.
```go title="Signature"
func (h *Hooks) OnListen(handler ...OnListenHandler)
```
<Tabs>
<TabItem value="onlisten-example" label="OnListen Example">
```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")
```
</TabItem>
</Tabs>
## OnFork
OnFork is a hook to execute user functions on Fork.
```go title="Signature"
func (h *Hooks) OnFork(handler ...OnForkHandler)
```
## OnShutdown
OnShutdown is a hook to execute user functions after Shutdown.
```go title="Signature"
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.
```go title="Signature"
func (h *Hooks) OnMount(handler ...OnMountHandler)
```
<Tabs>
<TabItem value="onmount-example" label="OnMount Example">
```go
package main
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
func main() {
app := New()
app.Get("/", testSimpleHandler).Name("x")
subApp := New()
subApp.Get("/test", testSimpleHandler)
subApp.Hooks().OnMount(func(parent *fiber.App) error {
fmt.Print("Mount path of parent app: "+parent.MountPath())
// ...
return nil
})
app.Mount("/sub", subApp)
}
// Result:
// Mount path of parent app:
```
</TabItem>
</Tabs>
:::caution
OnName/OnRoute/OnGroup/OnGroupName hooks are mount-sensitive. If you use one of these routes on sub app and you mount it; paths of routes and groups will start with mount prefix.

294
docs/guide/routing.md Normal file
View file

@ -0,0 +1,294 @@
---
id: routing
title: 🔌 Routing
description: >-
Routing refers to how an application's endpoints (URIs) respond to client
requests.
sidebar_position: 1
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import RoutingHandler from './../partials/routing/handler.md';
## Handlers
<RoutingHandler />
## Paths
Route paths, combined with a request method, define the endpoints at which requests can be made. Route paths can be **strings** or **string patterns**.
**Examples of route paths based on strings**
```go
// This route path will match requests to the root route, "/":
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("root")
})
// This route path will match requests to "/about":
app.Get("/about", func(c *fiber.Ctx) error {
return c.SendString("about")
})
// This route path will match requests to "/random.txt":
app.Get("/random.txt", func(c *fiber.Ctx) error {
return c.SendString("random.txt")
})
```
As with the expressJs framework, the order of the route declaration plays a role.
When a request is received, the routes are checked in the order in which they are declared.
:::info
So please be careful to write routes with variable parameters after the routes that contain fixed parts, so that these variable parts do not match instead and unexpected behavior occurs.
:::
## Parameters
Route parameters are dynamic elements in the route, which are **named** or **not named segments**. This segments that are used to capture the values specified at their position in the URL. The obtained values can be retrieved using the [Params](https://fiber.wiki/context#params) function, with the name of the route parameter specified in the path as their respective keys or for unnamed parameters the character\(\*, +\) and the counter of this.
The characters :, +, and \* are characters that introduce a parameter.
Greedy parameters are indicated by wildcard\(\*\) or plus\(+\) signs.
The routing also offers the possibility to use optional parameters, for the named parameters these are marked with a final "?", unlike the plus sign which is not optional, you can use the wildcard character for a parameter range which is optional and greedy.
**Example of define routes with route parameters**
```go
// Parameters
app.Get("/user/:name/books/:title", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s\n", c.Params("name"))
fmt.Fprintf(c, "%s\n", c.Params("title"))
return nil
})
// Plus - greedy - not optional
app.Get("/user/+", func(c *fiber.Ctx) error {
return c.SendString(c.Params("+"))
})
// Optional parameter
app.Get("/user/:name?", func(c *fiber.Ctx) error {
return c.SendString(c.Params("name"))
})
// Wildcard - greedy - optional
app.Get("/user/*", func(c *fiber.Ctx) error {
return c.SendString(c.Params("*"))
})
// This route path will match requests to "/v1/some/resource/name:customVerb", since the parameter character is escaped
app.Get(`/v1/some/resource/name\:customVerb`, func(c *fiber.Ctx) error {
return c.SendString("Hello, Community")
})
```
:::info
Since the hyphen \(`-`\) and the dot \(`.`\) are interpreted literally, they can be used along with route parameters for useful purposes.
:::
:::info
All special parameter characters can also be escaped with `"\\"` and lose their value, so you can use them in the route if you want, like in the custom methods of the [google api design guide](https://cloud.google.com/apis/design/custom_methods). It's recommended to use backticks `` ` `` because in go's regex documentation, they always use backticks to make sure it is unambiguous and the escape character doesn't interfere with regex patterns in an unexpected way.
:::
```go
// http://localhost:3000/plantae/prunus.persica
app.Get("/plantae/:genus.:species", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s.%s\n", c.Params("genus"), c.Params("species"))
return nil // prunus.persica
})
```
```go
// http://localhost:3000/flights/LAX-SFO
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s-%s\n", c.Params("from"), c.Params("to"))
return nil // LAX-SFO
})
```
Our intelligent router recognizes that the introductory parameter characters should be part of the request route in this case and can process them as such.
```go
// http://localhost:3000/shop/product/color:blue/size:xs
app.Get("/shop/product/color::color/size::size", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s:%s\n", c.Params("color"), c.Params("size"))
return nil // blue:xs
})
```
In addition, several parameters in a row and several unnamed parameter characters in the route, such as the wildcard or plus character, are possible, which greatly expands the possibilities of the router for the user.
```go
// GET /@v1
// Params: "sign" -> "@", "param" -> "v1"
app.Get("/:sign:param", handler)
// GET /api-v1
// Params: "name" -> "v1"
app.Get("/api-:name", handler)
// GET /customer/v1/cart/proxy
// Params: "*1" -> "customer/", "*2" -> "/cart"
app.Get("/*v1*/proxy", handler)
// GET /v1/brand/4/shop/blue/xs
// Params: "*1" -> "brand/4", "*2" -> "blue/xs"
app.Get("/v1/*/shop/*", handler)
```
We have adapted the routing strongly to the express routing, but currently without the possibility of the regular expressions, because they are quite slow. The possibilities can be tested with version 0.1.7 \(express 4\) in the online [Express route tester](http://forbeslindesay.github.io/express-route-tester/).
### Constraints
Route constraints execute when a match has occurred to the incoming URL and the URL path is tokenized into route values by parameters. The feature was intorduced in `v2.37.0` and inspired by [.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-6.0#route-constraints).
:::caution
Constraints aren't validation for parameters. If constraints aren't valid for a parameter value, Fiber returns **404 handler**.
:::
| Constraint | Example | Example matches |
| ----------------- | ------------------------------------ | ------------------------------------------------------------------------------------------- |
| int | `:id<int\>` | 123456789, -123456789 |
| bool | `:active<bool\>` | true,false |
| guid | `:id<guid\>` | CD2C1638-1638-72D5-1638-DEADBEEF1638 |
| float | `:weight<float\>` | 1.234, -1,001.01e8 |
| minLen(value) | `:username<minLen(4)\>` | Test (must be at least 4 characters) |
| maxLen(value) | `:filename<maxLen(8)\>` | MyFile (must be no more than 8 characters |
| len(length) | `:filename<len(12)\>` | somefile.txt (exactly 12 characters) |
| min(value) | `:age<min(18)\>` | 19 (Integer value must be at least 18) |
| max(value) | `:age<max(120)\>` | 91 (Integer value must be no more than 120) |
| range(min,max) | `:age<range(18,120)\>` | 91 (Integer value must be at least 18 but no more than 120) |
| alpha | `:name<alpha\>` | Rick (String must consist of one or more alphabetical characters, a-z and case-insensitive) |
| datetime | `:dob<datetime(2006\\\\-01\\\\-02)\>` | 2005-11-01 |
| regex(expression) | `:date<regex(\\d{4}-\\d{2}-\\d{2})\>` | 2022-08-27 (Must match regular expression) |
**Examples**
<Tabs>
<TabItem value="single-constraint" label="Single Constraint">
```go
app.Get("/:test<min(5)>", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/12
// 12
// curl -X GET http://localhost:3000/1
// Cannot GET /1
```
</TabItem>
<TabItem value="multiple-constraints" label="Multiple Constraints">
You can use `;` for multiple constraints.
```go
app.Get("/:test<min(100);maxLen(5)>", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/120000
// Cannot GET /120000
// curl -X GET http://localhost:3000/1
// Cannot GET /1
// curl -X GET http://localhost:3000/250
// 250
```
</TabItem>
<TabItem value="regex-constraint" label="Regex Constraint">
Fiber precompiles regex query when to register routes. So there're no performance overhead for regex constraint.
```go
app.Get(`/:date<regex(\d{4}-\d{2}-\d{2})>`, func(c *fiber.Ctx) error {
return c.SendString(c.Params("date"))
})
// curl -X GET http://localhost:3000/125
// Cannot GET /125
// curl -X GET http://localhost:3000/test
// Cannot GET /test
// curl -X GET http://localhost:3000/2022-08-27
// 2022-08-27
```
</TabItem>
</Tabs>
:::caution
You should use `\\` before routing-specific characters when to use datetime constraint (`*`, `+`, `?`, `:`, `/`, `<`, `>`, `;`, `(`, `)`), to avoid wrong parsing.
:::
**Optional Parameter Example**
You can impose constraints on optional parameters as well.
```go
app.Get("/:test<int>?", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/42
// 42
// curl -X GET http://localhost:3000/
//
// curl -X GET http://localhost:3000/7.0
// Cannot GET /7.0
```
## Middleware
Functions that are designed to make changes to the request or response are called **middleware functions**. The [Next](../api/ctx.md#next) is a **Fiber** router function, when called, executes the **next** function that **matches** the current route.
**Example of a middleware function**
```go
app.Use(func(c *fiber.Ctx) error {
// Set a custom header on all responses:
c.Set("X-Custom-Header", "Hello, World")
// Go to next middleware:
return c.Next()
})
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
```
`Use` method path is a **mount**, or **prefix** path, and limits middleware to only apply to any paths requested that begin with it.
### Constraints on Adding Routes Dynamically
:::caution
Adding routes dynamically after the application has started is not supported due to design and performance considerations. Make sure to define all your routes before the application starts.
:::
## Grouping
If you have many endpoints, you can organize your routes using `Group`.
```go
func main() {
app := fiber.New()
api := app.Group("/api", middleware) // /api
v1 := api.Group("/v1", middleware) // /api/v1
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2", middleware) // /api/v2
v2.Get("/list", handler) // /api/v2/list
v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000"))
}
```
More information about this in our [Grouping Guide](./grouping.md)

267
docs/guide/templates.md Normal file
View file

@ -0,0 +1,267 @@
---
id: templates
title: 📝 Templates
description: Fiber supports server-side template engines.
sidebar_position: 3
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Templates are a great tool to render dynamic content without using a separate frontend framework.
## Template Engines
Fiber allows you to provide a custom template engine at app initialization.
```go
app := fiber.New(fiber.Config{
// Pass in Views Template Engine
Views: engine,
// Default global path to search for views (can be overriden when calling Render())
ViewsLayout: "layouts/main",
// Enables/Disables access to `ctx.Locals()` entries in rendered views
// (defaults to false)
PassLocalsToViews: false,
})
```
### Supported Engines
The Fiber team maintains a [templates](https://docs.gofiber.io/template) package that provides wrappers for multiple template engines:
* [ace](https://docs.gofiber.io/template/ace/)
* [amber](https://docs.gofiber.io/template/amber/)
* [django](https://docs.gofiber.io/template/django/)
* [handlebars](https://docs.gofiber.io/template/handlebars)
* [html](https://docs.gofiber.io/template/html)
* [jet](https://docs.gofiber.io/template/jet)
* [mustache](https://docs.gofiber.io/template/mustache)
* [pug](https://docs.gofiber.io/template/pug)
* [slim](https://docs.gofiber.io/template/slim)
:::info
Custom template engines can implement the `Views` interface to be supported in Fiber.
:::
```go title="Views interface"
type Views interface {
// Fiber executes Load() on app initialization to load/parse the templates
Load() error
// Outputs a template to the provided buffer using the provided template,
// template name, and binded data
Render(io.Writer, string, interface{}, ...string) error
}
```
:::note
The `Render` method is linked to the [**ctx.Render\(\)**](../api/ctx.md#render) function that accepts a template name and binding data.
:::
## Rendering Templates
Once an engine is set up, a route handler can call the [**ctx.Render\(\)**](../api/ctx.md#render) function with a template name and binded data to send the rendered template.
```go title="Signature"
func (c *Ctx) Render(name string, bind Map, layouts ...string) error
```
:::info
By default, [**ctx.Render\(\)**](../api/ctx.md#render) searches for the template name in the `ViewsLayout` path. To override this setting, provide the path(s) in the `layouts` argument.
:::
<Tabs>
<TabItem value="example" label="Example">
```go
app.Get("/", func(c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"Title": "Hello, World!",
})
})
```
</TabItem>
<TabItem value="index" label="layouts/index.html">
```html
<!DOCTYPE html>
<html>
<body>
<h1>{{.Title}}</h1>
</body>
</html>
```
</TabItem>
</Tabs>
:::caution
If the Fiber config option `PassLocalsToViews` is enabled, then all locals set using `ctx.Locals(key, value)` will be passed to the template. It is important to avoid clashing keys when using this setting.
:::
## Advanced Templating
### Custom Functions
Fiber supports adding custom functions to templates.
#### AddFunc
Adds a global function to all templates.
```go title="Signature"
func (e *Engine) AddFunc(name string, fn interface{}) IEngineCore
```
<Tabs>
<TabItem value="add-func-example" label="AddFunc Example">
```go
// Add `ToUpper` to engine
engine := html.New("./views", ".html")
engine.AddFunc("ToUpper", func(s string) string {
return strings.ToUpper(s)
}
// Initialize Fiber App
app := fiber.New(fiber.Config{
Views: engine,
})
app.Get("/", func (c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"Content": "hello, world!"
})
})
```
</TabItem>
<TabItem value="add-func-template" label="views/index.html">
```html
<!DOCTYPE html>
<html>
<body>
<p>This will be in {{ToUpper "all caps"}}:</p>
<p>{{ToUpper .Content}}</p>
</body>
</html>
```
</TabItem>
</Tabs>
#### AddFuncMap
Adds a Map of functions (keyed by name) to all templates.
```go title="Signature"
func (e *Engine) AddFuncMap(m map[string]interface{}) IEngineCore
```
<Tabs>
<TabItem value="add-func-map-example" label="AddFuncMap Example">
```go
// Add `ToUpper` to engine
engine := html.New("./views", ".html")
engine.AddFuncMap(map[string]interface{}{
"ToUpper": func(s string) string {
return strings.ToUpper(s)
},
})
// Initialize Fiber App
app := fiber.New(fiber.Config{
Views: engine,
})
app.Get("/", func (c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"Content": "hello, world!"
})
})
```
</TabItem>
<TabItem value="add-func-map-template" label="views/index.html">
```html
<!DOCTYPE html>
<html>
<body>
<p>This will be in {{ToUpper "all caps"}}:</p>
<p>{{ToUpper .Content}}</p>
</body>
</html>
```
</TabItem>
</Tabs>
* For more advanced template documentation, please visit the [gofiber/template GitHub Repository](https://github.com/gofiber/template).
## Full Example
<Tabs>
<TabItem value="example" label="Example">
```go
package main
import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html/v2"
)
func main() {
// Initialize standard Go html template engine
engine := html.New("./views", ".html")
// If you want to use another engine,
// just replace with following:
// Create a new engine with django
// engine := django.New("./views", ".django")
app := fiber.New(fiber.Config{
Views: engine,
})
app.Get("/", func(c *fiber.Ctx) error {
// Render index template
return c.Render("index", fiber.Map{
"Title": "Go Fiber Template Example",
"Description": "An example template",
"Greeting": "Hello, world!",
});
})
log.Fatal(app.Listen(":3000"))
}
```
</TabItem>
<TabItem value="index" label="views/index.html">
```html
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
<meta name="description" content="{{.Description}}">
</head>
<body>
<h1>{{.Title}}</h1>
<p>{{.Greeting}}</p>
</body>
</html>
```
</TabItem>
</Tabs>

168
docs/guide/validation.md Normal file
View file

@ -0,0 +1,168 @@
---
id: validation
title: 🔎 Validation
sidebar_position: 5
---
## Validator package
Fiber can make _great_ use of the validator package to ensure correct validation of data to store.
- [Official validator Github page \(Installation, use, examples..\).](https://github.com/go-playground/validator)
You can find the detailed descriptions of the _validations_ used in the fields contained on the structs below:
- [Detailed docs](https://pkg.go.dev/github.com/go-playground/validator?tab=doc)
```go title="Validation Example"
package main
import (
"fmt"
"log"
"strings"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
)
type (
User struct {
Name string `validate:"required,min=5,max=20"` // Required field, min 5 char long max 20
Age int `validate:"required,teener"` // Required field, and client needs to implement our 'teener' tag format which we'll see later
}
ErrorResponse struct {
Error bool
FailedField string
Tag string
Value interface{}
}
XValidator struct {
validator *validator.Validate
}
GlobalErrorHandlerResp struct {
Success bool `json:"success"`
Message string `json:"message"`
}
)
// This is the validator instance
// for more information see: https://github.com/go-playground/validator
var validate = validator.New()
func (v XValidator) Validate(data interface{}) []ErrorResponse {
validationErrors := []ErrorResponse{}
errs := validate.Struct(data)
if errs != nil {
for _, err := range errs.(validator.ValidationErrors) {
// In this case data object is actually holding the User struct
var elem ErrorResponse
elem.FailedField = err.Field() // Export struct field name
elem.Tag = err.Tag() // Export struct tag
elem.Value = err.Value() // Export field value
elem.Error = true
validationErrors = append(validationErrors, elem)
}
}
return validationErrors
}
func main() {
myValidator := &XValidator{
validator: validate,
}
app := fiber.New(fiber.Config{
// Global custom error handler
ErrorHandler: func(c *fiber.Ctx, err error) error {
return c.Status(fiber.StatusBadRequest).JSON(GlobalErrorHandlerResp{
Success: false,
Message: err.Error(),
})
},
})
// Custom struct validation tag format
myValidator.validator.RegisterValidation("teener", func(fl validator.FieldLevel) bool {
// User.Age needs to fit our needs, 12-18 years old.
return fl.Field().Int() >= 12 && fl.Field().Int() <= 18
})
app.Get("/", func(c *fiber.Ctx) error {
user := &User{
Name: c.Query("name"),
Age: c.QueryInt("age"),
}
// Validation
if errs := myValidator.Validate(user); len(errs) > 0 && errs[0].Error {
errMsgs := make([]string, 0)
for _, err := range errs {
errMsgs = append(errMsgs, fmt.Sprintf(
"[%s]: '%v' | Needs to implement '%s'",
err.FailedField,
err.Value,
err.Tag,
))
}
return &fiber.Error{
Code: fiber.ErrBadRequest.Code,
Message: strings.Join(errMsgs, " and "),
}
}
// Logic, validated with success
return c.SendString("Hello, World!")
})
log.Fatal(app.Listen(":3000"))
}
/**
OUTPUT
[1]
Request:
GET http://127.0.0.1:3000/
Response:
{"success":false,"message":"[Name]: '' | Needs to implement 'required' and [Age]: '0' | Needs to implement 'required'"}
[2]
Request:
GET http://127.0.0.1:3000/?name=efdal&age=9
Response:
{"success":false,"message":"[Age]: '9' | Needs to implement 'teener'"}
[3]
Request:
GET http://127.0.0.1:3000/?name=efdal&age=
Response:
{"success":false,"message":"[Age]: '0' | Needs to implement 'required'"}
[4]
Request:
GET http://127.0.0.1:3000/?name=efdal&age=18
Response:
Hello, World!
**/
```