diff --git a/ctx.go b/ctx.go index aecfacdcfdb..07ffb1db0df 100644 --- a/ctx.go +++ b/ctx.go @@ -54,6 +54,8 @@ type DefaultCtx struct { fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx bind *Bind // Default bind reference redirect *Redirect // Default redirect reference + req *DefaultReq // Default request api reference + res *DefaultRes // Default response api reference values [maxParams]string // Route parameter values viewBindMap sync.Map // Default view map to bind template engine method string // HTTP method @@ -1463,6 +1465,18 @@ func (c *DefaultCtx) renderExtensions(bind any) { } } +// Req returns a convenience type whose API is limited to operations +// on the incoming request. +func (c *DefaultCtx) Req() Req { + return c.req +} + +// Res returns a convenience type whose API is limited to operations +// on the outgoing response. +func (c *DefaultCtx) Res() Res { + return c.res +} + // Route returns the matched Route struct. func (c *DefaultCtx) Route() *Route { if c.route == nil { diff --git a/ctx_interface.go b/ctx_interface.go index ca438d82c52..32e8ee392b4 100644 --- a/ctx_interface.go +++ b/ctx_interface.go @@ -32,10 +32,14 @@ type CustomCtx interface { func NewDefaultCtx(app *App) *DefaultCtx { // return ctx - return &DefaultCtx{ + ctx := &DefaultCtx{ // Set app reference app: app, } + ctx.req = &DefaultReq{ctx: ctx} + ctx.res = &DefaultRes{ctx: ctx} + + return ctx } func (app *App) newCtx() Ctx { diff --git a/ctx_interface_gen.go b/ctx_interface_gen.go index 101068a269d..fffe218d228 100644 --- a/ctx_interface_gen.go +++ b/ctx_interface_gen.go @@ -265,6 +265,12 @@ type Ctx interface { // We support the following engines: https://github.com/gofiber/template Render(name string, bind any, layouts ...string) error renderExtensions(bind any) + // Req returns a convenience type whose API is limited to operations + // on the incoming request. + Req() Req + // Res returns a convenience type whose API is limited to operations + // on the outgoing response. + Res() Res // Route returns the matched Route struct. Route() *Route // SaveFile saves any multipart file to disk. diff --git a/ctx_test.go b/ctx_test.go index 082b0d442ca..ee272d244b9 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -46,7 +46,7 @@ func Test_Ctx_Accepts(t *testing.T) { c.Request().Header.Set(HeaderAccept, "text/html,application/xhtml+xml,application/xml;q=0.9") require.Equal(t, "", c.Accepts("")) - require.Equal(t, "", c.Accepts()) + require.Equal(t, "", c.Req().Accepts()) require.Equal(t, ".xml", c.Accepts(".xml")) require.Equal(t, "", c.Accepts(".john")) require.Equal(t, "application/xhtml+xml", c.Accepts("application/xml", "application/xml+rss", "application/yaml", "application/xhtml+xml"), "must use client-preferred mime type") @@ -57,13 +57,13 @@ func Test_Ctx_Accepts(t *testing.T) { c.Request().Header.Set(HeaderAccept, "text/*, application/json") require.Equal(t, "html", c.Accepts("html")) require.Equal(t, "text/html", c.Accepts("text/html")) - require.Equal(t, "json", c.Accepts("json", "text")) + require.Equal(t, "json", c.Req().Accepts("json", "text")) require.Equal(t, "application/json", c.Accepts("application/json")) require.Equal(t, "", c.Accepts("image/png")) require.Equal(t, "", c.Accepts("png")) c.Request().Header.Set(HeaderAccept, "text/html, application/json") - require.Equal(t, "text/*", c.Accepts("text/*")) + require.Equal(t, "text/*", c.Req().Accepts("text/*")) c.Request().Header.Set(HeaderAccept, "*/*") require.Equal(t, "html", c.Accepts("html")) @@ -968,46 +968,46 @@ func Test_Ctx_Cookie(t *testing.T) { Expires: expire, // SameSite: CookieSameSiteStrictMode, // default is "lax" } - c.Cookie(cookie) + c.Res().Cookie(cookie) expect := "username=john; expires=" + httpdate + "; path=/; SameSite=Lax" - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) expect = "username=john; expires=" + httpdate + "; path=/" cookie.SameSite = CookieSameSiteDisabled - c.Cookie(cookie) - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + c.Res().Cookie(cookie) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) expect = "username=john; expires=" + httpdate + "; path=/; SameSite=Strict" cookie.SameSite = CookieSameSiteStrictMode - c.Cookie(cookie) - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + c.Res().Cookie(cookie) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) expect = "username=john; expires=" + httpdate + "; path=/; secure; SameSite=None" cookie.Secure = true cookie.SameSite = CookieSameSiteNoneMode - c.Cookie(cookie) - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + c.Res().Cookie(cookie) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) expect = "username=john; path=/; secure; SameSite=None" // should remove expires and max-age headers cookie.SessionOnly = true cookie.Expires = expire cookie.MaxAge = 10000 - c.Cookie(cookie) - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + c.Res().Cookie(cookie) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) expect = "username=john; path=/; secure; SameSite=None" // should remove expires and max-age headers when no expire and no MaxAge (default time) cookie.SessionOnly = false cookie.Expires = time.Time{} cookie.MaxAge = 0 - c.Cookie(cookie) - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + c.Res().Cookie(cookie) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) expect = "username=john; path=/; secure; SameSite=None; Partitioned" cookie.Partitioned = true - c.Cookie(cookie) - require.Equal(t, expect, string(c.Response().Header.Peek(HeaderSetCookie))) + c.Res().Cookie(cookie) + require.Equal(t, expect, c.Res().Get(HeaderSetCookie)) } // go test -v -run=^$ -bench=Benchmark_Ctx_Cookie -benchmem -count=4 @@ -1033,8 +1033,8 @@ func Test_Ctx_Cookies(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.Set("Cookie", "john=doe") - require.Equal(t, "doe", c.Cookies("john")) - require.Equal(t, "default", c.Cookies("unknown", "default")) + require.Equal(t, "doe", c.Req().Cookies("john")) + require.Equal(t, "default", c.Req().Cookies("unknown", "default")) } // go test -run Test_Ctx_Format @@ -1058,13 +1058,13 @@ func Test_Ctx_Format(t *testing.T) { } c.Request().Header.Set(HeaderAccept, `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7`) - err := c.Format(formatHandlers("application/xhtml+xml", "application/xml", "foo/bar")...) + err := c.Res().Format(formatHandlers("application/xhtml+xml", "application/xml", "foo/bar")...) require.Equal(t, "application/xhtml+xml", accepted) require.Equal(t, "application/xhtml+xml", c.GetRespHeader(HeaderContentType)) require.NoError(t, err) require.NotEqual(t, StatusNotAcceptable, c.Response().StatusCode()) - err = c.Format(formatHandlers("foo/bar;a=b")...) + err = c.Res().Format(formatHandlers("foo/bar;a=b")...) require.Equal(t, "foo/bar;a=b", accepted) require.Equal(t, "foo/bar;a=b", c.GetRespHeader(HeaderContentType)) require.NoError(t, err) @@ -1165,7 +1165,7 @@ func Test_Ctx_AutoFormat(t *testing.T) { require.Equal(t, "Hello, World!", string(c.Response().Body())) c.Request().Header.Set(HeaderAccept, MIMETextHTML) - err = c.AutoFormat("Hello, World!") + err = c.Res().AutoFormat("Hello, World!") require.NoError(t, err) require.Equal(t, "

Hello, World!

", string(c.Response().Body())) @@ -1175,7 +1175,7 @@ func Test_Ctx_AutoFormat(t *testing.T) { require.Equal(t, `"Hello, World!"`, string(c.Response().Body())) c.Request().Header.Set(HeaderAccept, MIMETextPlain) - err = c.AutoFormat(complex(1, 1)) + err = c.Res().AutoFormat(complex(1, 1)) require.NoError(t, err) require.Equal(t, "(1+1i)", string(c.Response().Body())) @@ -2939,7 +2939,7 @@ func Test_Ctx_SaveFile(t *testing.T) { app := New() app.Post("/test", func(c Ctx) error { - fh, err := c.FormFile("file") + fh, err := c.Req().FormFile("file") require.NoError(t, err) tempFile, err := os.CreateTemp(os.TempDir(), "test-") @@ -3075,7 +3075,7 @@ func Test_Ctx_ClearCookie(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.Set(HeaderCookie, "john=doe") - c.ClearCookie("john") + c.Res().ClearCookie("john") require.True(t, strings.HasPrefix(string(c.Response().Header.Peek(HeaderSetCookie)), "john=; expires=")) c.Request().Header.Set(HeaderCookie, "test1=dummy") @@ -3104,7 +3104,7 @@ func Test_Ctx_Download(t *testing.T) { require.Equal(t, expect, c.Response().Body()) require.Equal(t, `attachment; filename="Awesome+File%21"`, string(c.Response().Header.Peek(HeaderContentDisposition))) - require.NoError(t, c.Download("ctx.go")) + require.NoError(t, c.Res().Download("ctx.go")) require.Equal(t, `attachment; filename="ctx.go"`, string(c.Response().Header.Peek(HeaderContentDisposition))) } @@ -3136,7 +3136,7 @@ func Test_Ctx_SendFile(t *testing.T) { // test with custom error code c = app.AcquireCtx(&fasthttp.RequestCtx{}) - err = c.Status(StatusInternalServerError).SendFile("ctx.go") + err = c.Res().Status(StatusInternalServerError).SendFile("ctx.go") // check expectation require.NoError(t, err) require.Equal(t, expectFileContent, c.Response().Body()) @@ -3161,7 +3161,7 @@ func Test_Ctx_SendFile_ContentType(t *testing.T) { // 1) simple case c := app.AcquireCtx(&fasthttp.RequestCtx{}) - err := c.SendFile("./.github/testdata/fs/img/fiber.png") + err := c.Res().SendFile("./.github/testdata/fs/img/fiber.png") // check expectation require.NoError(t, err) require.Equal(t, StatusOK, c.Response().StatusCode()) @@ -3782,7 +3782,7 @@ func Test_Ctx_JSONP(t *testing.T) { require.Equal(t, `callback({"Age":20,"Name":"Grame"});`, string(c.Response().Body())) require.Equal(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type"))) - err = c.JSONP(Map{ + err = c.Res().JSONP(Map{ "Name": "Grame", "Age": 20, }, "john") @@ -4006,7 +4006,7 @@ func Test_Ctx_Render(t *testing.T) { err = c.Render("./.github/testdata/template-non-exists.html", nil) require.Error(t, err) - err = c.Render("./.github/testdata/template-invalid.html", nil) + err = c.Res().Render("./.github/testdata/template-invalid.html", nil) require.Error(t, err) } @@ -4907,7 +4907,7 @@ func Test_Ctx_Queries(t *testing.T) { c.Request().URI().SetQueryString("tags=apple,orange,banana&filters[tags]=apple,orange,banana&filters[category][name]=fruits&filters.tags=apple,orange,banana&filters.category.name=fruits") - queries = c.Queries() + queries = c.Req().Queries() require.Equal(t, "apple,orange,banana", queries["tags"]) require.Equal(t, "apple,orange,banana", queries["filters[tags]"]) require.Equal(t, "fruits", queries["filters[category][name]"]) @@ -5055,7 +5055,7 @@ func Test_Ctx_IsFromLocal_X_Forwarded(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) c.Request().Header.Set(HeaderXForwardedFor, "93.46.8.90") - require.False(t, c.IsFromLocal()) + require.False(t, c.Req().IsFromLocal()) } } @@ -5088,8 +5088,8 @@ func Test_Ctx_IsFromLocal_RemoteAddr(t *testing.T) { fastCtx := &fasthttp.RequestCtx{} fastCtx.SetRemoteAddr(localIPv6) c := app.AcquireCtx(fastCtx) - require.Equal(t, "::1", c.IP()) - require.True(t, c.IsFromLocal()) + require.Equal(t, "::1", c.Req().IP()) + require.True(t, c.Req().IsFromLocal()) } // Test for the case fasthttp remoteAddr is set to "0:0:0:0:0:0:0:1". { diff --git a/docs/api/ctx.md b/docs/api/ctx.md index fda9f373282..312f997ac30 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -8,98 +8,7 @@ description: >- sidebar_position: 3 --- -## Accepts - -Checks if the specified **extensions** or **content** **types** are acceptable. - -:::info -Based on the request’s [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. -::: - -```go title="Signature" -func (c fiber.Ctx) Accepts(offers ...string) string -func (c fiber.Ctx) AcceptsCharsets(offers ...string) string -func (c fiber.Ctx) AcceptsEncodings(offers ...string) string -func (c fiber.Ctx) AcceptsLanguages(offers ...string) string -``` - -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.Accepts("html") // "html" - c.Accepts("text/html") // "text/html" - c.Accepts("json", "text") // "json" - c.Accepts("application/json") // "application/json" - c.Accepts("text/plain", "application/json") // "application/json", due to quality - c.Accepts("image/png") // "" - c.Accepts("png") // "" - // ... -}) -``` - -```go title="Example 2" -// Accept: text/html, text/*, application/json, */*; q=0 - -app.Get("/", func(c fiber.Ctx) error { - c.Accepts("text/plain", "application/json") // "application/json", due to specificity - c.Accepts("application/json", "text/html") // "text/html", due to first match - c.Accepts("image/png") // "", due to */* with q=0 is Not Acceptable - // ... -}) -``` - -Media-Type parameters are supported. - -```go title="Example 3" -// Accept: text/plain, application/json; version=1; foo=bar - -app.Get("/", func(c fiber.Ctx) error { - // Extra parameters in the accept are ignored - c.Accepts("text/plain;format=flowed") // "text/plain;format=flowed" - - // An offer must contain all parameters present in the Accept type - c.Accepts("application/json") // "" - - // Parameter order and capitalization do not matter. Quotes on values are stripped. - c.Accepts(`application/json;foo="bar";VERSION=1`) // "application/json;foo="bar";VERSION=1" -}) -``` - -```go title="Example 4" -// Accept: text/plain;format=flowed;q=0.9, text/plain -// i.e., "I prefer text/plain;format=flowed less than other forms of text/plain" - -app.Get("/", func(c fiber.Ctx) error { - // Beware: the order in which offers are listed matters. - // Although the client specified they prefer not to receive format=flowed, - // the text/plain Accept matches with "text/plain;format=flowed" first, so it is returned. - c.Accepts("text/plain;format=flowed", "text/plain") // "text/plain;format=flowed" - - // Here, things behave as expected: - c.Accepts("text/plain", "text/plain;format=flowed") // "text/plain" -}) -``` - -Fiber provides similar functions for the other accept headers. - -```go -// Accept-Charset: utf-8, iso-8859-1;q=0.2 -// Accept-Encoding: gzip, compress;q=0.2 -// Accept-Language: en;q=0.8, nl, ru - -app.Get("/", func(c fiber.Ctx) error { - c.AcceptsCharsets("utf-16", "iso-8859-1") - // "iso-8859-1" - - c.AcceptsEncodings("compress", "br") - // "compress" - - c.AcceptsLanguages("pt", "nl", "ru") - // "nl" - // ... -}) -``` - -## App +### App Returns the [\*App](app.md) reference so you can easily access all application settings. @@ -113,141 +22,94 @@ app.Get("/stack", func(c fiber.Ctx) error { }) ``` -## Append +### Bind -Appends the specified **value** to the HTTP response header field. +Bind is a method that supports bindings for the request/response body, query parameters, URL parameters, cookies, and much more. +It returns a pointer to the [Bind](./bind.md) struct which contains all the methods to bind the request/response data. -:::caution -If the header is **not** already set, it creates the header with the specified value. -::: +For detailed information, check the [Bind](./bind.md) documentation. ```go title="Signature" -func (c fiber.Ctx) Append(field string, values ...string) +func (c fiber.Ctx) Bind() *Bind ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.Append("Link", "http://google.com", "http://localhost") - // => Link: http://google.com, http://localhost - - c.Append("Link", "Test") - // => Link: http://google.com, http://localhost, Test - - // ... +app.Post("/", func(c fiber.Ctx) error { + user := new(User) + // Bind the request body to a struct: + return c.Bind().Body(user) }) ``` -## Attachment +### Context -Sets the HTTP response [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header field to `attachment`. +`Context` returns a context implementation that was set by the user earlier or returns a non-nil, empty context if it was not set earlier. ```go title="Signature" -func (c fiber.Ctx) Attachment(filename ...string) +func (c fiber.Ctx) Context() context.Context ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - c.Attachment() - // => Content-Disposition: attachment - - c.Attachment("./upload/images/logo.png") - // => Content-Disposition: attachment; filename="logo.png" - // => Content-Type: image/png + ctx := c.Context() + // ctx is context implementation set by user // ... }) ``` -## AutoFormat +### Drop -Performs content-negotiation on the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. It uses [Accepts](ctx.md#accepts) to select a proper format. -The supported content types are `text/html`, `text/plain`, `application/json`, and `application/xml`. -For more flexible content negotiation, use [Format](ctx.md#format). +Terminates the client connection silently without sending any HTTP headers or response body. -:::info -If the header is **not** specified or there is **no** proper format, **text/plain** is used. -::: +This can be used for scenarios where you want to block certain requests without notifying the client, such as mitigating +DDoS attacks or protecting sensitive endpoints from unauthorized access. ```go title="Signature" -func (c fiber.Ctx) AutoFormat(body any) error +func (c fiber.Ctx) Drop() error ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - // Accept: text/plain - c.AutoFormat("Hello, World!") - // => Hello, World! - - // Accept: text/html - c.AutoFormat("Hello, World!") - // =>

Hello, World!

- - type User struct { - Name string + if c.IP() == "192.168.1.1" { + return c.Drop() } - user := User{"John Doe"} - - // Accept: application/json - c.AutoFormat(user) - // => {"Name":"John Doe"} - // Accept: application/xml - c.AutoFormat(user) - // => John Doe - // .. + return c.SendString("Hello World!") }) ``` -## BaseURL +### GetReqHeaders -Returns the base URL (**protocol** + **host**) as a `string`. +Returns the HTTP request headers as a map. Since a header can be set multiple times in a single request, the values of the map are slices of strings containing all the different values of the header. ```go title="Signature" -func (c fiber.Ctx) BaseURL() string -``` - -```go title="Example" -// GET https://example.com/page#chapter-1 - -app.Get("/", func(c fiber.Ctx) error { - c.BaseURL() // "https://example.com" - // ... -}) +func (c fiber.Ctx) GetReqHeaders() map[string][]string ``` -## Bind - -Bind is a method that supports bindings for the request/response body, query parameters, URL parameters, cookies, and much more. -It returns a pointer to the [Bind](./bind.md) struct which contains all the methods to bind the request/response data. - -For detailed information, check the [Bind](./bind.md) documentation. - -```go title="Signature" -func (c fiber.Ctx) Bind() *Bind -``` +:::info +Returned value is only valid within the handler. Do not store any references. +Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) +::: -```go title="Example" -app.Post("/", func(c fiber.Ctx) error { - user := new(User) - // Bind the request body to a struct: - return c.Bind().Body(user) -}) -``` +### GetRespHeader -## Body +Returns the HTTP response header specified by the field. -As per the header `Content-Encoding`, this method will try to perform a file decompression from the **body** bytes. In case no `Content-Encoding` header is sent, it will perform as [BodyRaw](#bodyraw). +:::tip +The match is **case-insensitive**. +::: ```go title="Signature" -func (c fiber.Ctx) Body() []byte +func (c fiber.Ctx) GetRespHeader(key string, defaultValue ...string) string ``` ```go title="Example" -// echo 'user=john' | gzip | curl -v -i --data-binary @- -H "Content-Encoding: gzip" http://localhost:8080 - -app.Post("/", func(c fiber.Ctx) error { - // Decompress body from POST request based on the Content-Encoding and return the raw content: - return c.Send(c.Body()) // []byte("user=john") +app.Get("/", func(c fiber.Ctx) error { + c.GetRespHeader("X-Request-Id") // "8d7ad5e3-aaf3-450b-a241-2beb887efd54" + c.GetRespHeader("Content-Type") // "text/plain" + c.GetRespHeader("something", "john") // "john" + // .. }) ``` @@ -256,21 +118,12 @@ Returned value is only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) ::: -## BodyRaw +### GetRespHeaders -Returns the raw request **body**. +Returns the HTTP response headers as a map. Since a header can be set multiple times in a single request, the values of the map are slices of strings containing all the different values of the header. ```go title="Signature" -func (c fiber.Ctx) BodyRaw() []byte -``` - -```go title="Example" -// curl -X POST http://localhost:8080 -d user=john - -app.Post("/", func(c fiber.Ctx) error { - // Get raw body from POST request: - return c.Send(c.BodyRaw()) // []byte("user=john") -}) +func (c fiber.Ctx) GetRespHeaders() map[string][]string ``` :::info @@ -278,425 +131,430 @@ Returned value is only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) ::: -## ClearCookie +### GetRouteURL -Expires a client cookie (or all cookies if left empty). +Generates URLs to named routes, with parameters. URLs are relative, for example: "/user/1831" ```go title="Signature" -func (c fiber.Ctx) ClearCookie(key ...string) +func (c fiber.Ctx) GetRouteURL(routeName string, params Map) (string, error) ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - // Clears all cookies: - c.ClearCookie() + return c.SendString("Home page") +}).Name("home") - // Expire specific cookie by name: - c.ClearCookie("user") +app.Get("/user/:id", func(c fiber.Ctx) error { + return c.SendString(c.Params("id")) +}).Name("user.show") - // Expire multiple cookies by names: - c.ClearCookie("token", "session", "track_id", "version") - // ... +app.Get("/test", func(c fiber.Ctx) error { + location, _ := c.GetRouteURL("user.show", fiber.Map{"id": 1}) + return c.SendString(location) }) + +// /test returns "/user/1" ``` -:::caution -Web browsers and other compliant clients will only clear the cookie if the given options are identical to those when creating the cookie, excluding `Expires` and `MaxAge`. `ClearCookie` will not set these values for you - a technique similar to the one shown below should be used to ensure your cookie is deleted. +### Locals + +A method that stores variables scoped to the request and, therefore, are available only to the routes that match the request. The stored variables are removed after the request is handled. If any of the stored data implements the `io.Closer` interface, its `Close` method will be called before it's removed. + +:::tip +This is useful if you want to pass some **specific** data to the next middleware. Remember to perform type assertions when retrieving the data to ensure it is of the expected type. You can also use a non-exported type as a key to avoid collisions. ::: +```go title="Signature" +func (c fiber.Ctx) Locals(key any, value ...any) any +``` + ```go title="Example" -app.Get("/set", func(c fiber.Ctx) error { - c.Cookie(&fiber.Cookie{ - Name: "token", - Value: "randomvalue", - Expires: time.Now().Add(24 * time.Hour), - HTTPOnly: true, - SameSite: "lax", - }) - // ... -}) +// keyType is an unexported type for keys defined in this package. +// This prevents collisions with keys defined in other packages. +type keyType int -app.Get("/delete", func(c fiber.Ctx) error { - c.Cookie(&fiber.Cookie{ - Name: "token", - // Set expiry date to the past - Expires: time.Now().Add(-(time.Hour * 2)), - HTTPOnly: true, - SameSite: "lax", - }) +// userKey is the key for user.User values in Contexts. It is +// unexported; clients use user.NewContext and user.FromContext +// instead of using this key directly. +var userKey keyType - // ... +app.Use(func(c fiber.Ctx) error { + c.Locals(userKey, "admin") // Stores the string "admin" under a non-exported type key + return c.Next() }) -``` -## ClientHelloInfo +app.Get("/admin", func(c fiber.Ctx) error { + user, ok := c.Locals(userKey).(string) // Retrieves the data stored under the key and performs a type assertion + if ok && user == "admin" { + return c.Status(fiber.StatusOK).SendString("Welcome, admin!") + } + return c.SendStatus(fiber.StatusForbidden) +}) +``` -`ClientHelloInfo` contains information from a ClientHello message in order to guide application logic in the `GetCertificate` and `GetConfigForClient` callbacks. -You can refer to the [ClientHelloInfo](https://golang.org/pkg/crypto/tls/#ClientHelloInfo) struct documentation for more information on the returned struct. +An alternative version of the `Locals` method that takes advantage of Go's generics feature is also available. This version allows for the manipulation and retrieval of local values within a request's context with a more specific data type. ```go title="Signature" -func (c fiber.Ctx) ClientHelloInfo() *tls.ClientHelloInfo +func Locals[V any](c fiber.Ctx, key any, value ...V) V ``` ```go title="Example" -// GET http://example.com/hello -app.Get("/hello", func(c fiber.Ctx) error { - chi := c.ClientHelloInfo() - // ... +app.Use(func(c fiber.Ctx) error { + fiber.Locals[string](c, "john", "doe") + fiber.Locals[int](c, "age", 18) + fiber.Locals[bool](c, "isHuman", true) + return c.Next() }) -``` -## Context +app.Get("/test", func(c fiber.Ctx) error { + fiber.Locals[string](c, "john") // "doe" + fiber.Locals[int](c, "age") // 18 + fiber.Locals[bool](c, "isHuman") // true + return nil +}) +```` -`Context` returns a context implementation that was set by the user earlier or returns a non-nil, empty context if it was not set earlier. +Make sure to understand and correctly implement the `Locals` method in both its standard and generic form for better control over route-specific data within your application. + +### Next + +When **Next** is called, it executes the next method in the stack that matches the current route. You can pass an error struct within the method that will end the chaining and call the [error handler](https://docs.gofiber.io/guide/error-handling). ```go title="Signature" -func (c fiber.Ctx) Context() context.Context +func (c fiber.Ctx) Next() error ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - ctx := c.Context() - // ctx is context implementation set by user + fmt.Println("1st route!") + return c.Next() +}) - // ... +app.Get("*", func(c fiber.Ctx) error { + fmt.Println("2nd route!") + return c.Next() +}) + +app.Get("/", func(c fiber.Ctx) error { + fmt.Println("3rd route!") + return c.SendString("Hello, World!") }) ``` -## Cookie +### Redirect -Sets a cookie. +Returns the Redirect reference. -```go title="Signature" -func (c fiber.Ctx) Cookie(cookie *Cookie) -``` +For detailed information, check the [Redirect](./redirect.md) documentation. -```go -type Cookie struct { - Name string `json:"name"` // The name of the cookie - Value string `json:"value"` // The value of the cookie - Path string `json:"path"` // Specifies a URL path which is allowed to receive the cookie - Domain string `json:"domain"` // Specifies the domain which is allowed to receive the cookie - MaxAge int `json:"max_age"` // The maximum age (in seconds) of the cookie - Expires time.Time `json:"expires"` // The expiration date of the cookie - Secure bool `json:"secure"` // Indicates that the cookie should only be transmitted over a secure HTTPS connection - HTTPOnly bool `json:"http_only"` // Indicates that the cookie is accessible only through the HTTP protocol - SameSite string `json:"same_site"` // Controls whether or not a cookie is sent with cross-site requests - Partitioned bool `json:"partitioned"` // Indicates if the cookie is stored in a partitioned cookie jar - SessionOnly bool `json:"session_only"` // Indicates if the cookie is a session-only cookie -} +```go title="Signature" +func (c fiber.Ctx) Redirect() *Redirect ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - // Create cookie - cookie := new(fiber.Cookie) - cookie.Name = "john" - cookie.Value = "doe" - cookie.Expires = time.Now().Add(24 * time.Hour) - - // Set cookie - c.Cookie(cookie) - // ... +app.Get("/coffee", func(c fiber.Ctx) error { + return c.Redirect().To("/teapot") }) -``` - -:::info -Partitioned cookies allow partitioning the cookie jar by top-level site, enhancing user privacy by preventing cookies from being shared across different sites. This feature is particularly useful in scenarios where a user interacts with embedded third-party services that should not have access to the main site's cookies. You can check out [CHIPS](https://developers.google.com/privacy-sandbox/3pcd/chips) for more information. -::: - -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - // Create a new partitioned cookie - cookie := new(fiber.Cookie) - cookie.Name = "user_session" - cookie.Value = "abc123" - cookie.Partitioned = true // This cookie will be stored in a separate jar when it's embedded into another website - // Set the cookie in the response - c.Cookie(cookie) - return c.SendString("Partitioned cookie set") +app.Get("/teapot", func(c fiber.Ctx) error { + return c.Status(fiber.StatusTeapot).Send("🍵 short and stout 🍵") }) ``` -## Cookies +### Request -Gets a cookie value by key. You can pass an optional default value that will be returned if the cookie key does not exist. +Returns the [*fasthttp.Request](https://pkg.go.dev/github.com/valyala/fasthttp#Request) pointer. ```go title="Signature" -func (c fiber.Ctx) Cookies(key string, defaultValue ...string) string +func (c fiber.Ctx) Request() *fasthttp.Request ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - // Get cookie by key: - c.Cookies("name") // "john" - c.Cookies("empty", "doe") // "doe" - // ... + c.Request().Header.Method() + // => []byte("GET") }) ``` +### RequestCtx + +Returns [\*fasthttp.RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) that is compatible with the `context.Context` interface that requires a deadline, a cancellation signal, and other values across API boundaries. + +```go title="Signature" +func (c fiber.Ctx) RequestCtx() *fasthttp.RequestCtx +``` + :::info -Returned value is only valid within the handler. Do not store any references. -Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) +Please read the [Fasthttp Documentation](https://pkg.go.dev/github.com/valyala/fasthttp?tab=doc) for more information. ::: -## Download +### Response -Transfers the file from the given path as an `attachment`. - -Typically, browsers will prompt the user to download. By default, the [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header `filename=` parameter is the file path (_this typically appears in the browser dialog_). -Override this default with the **filename** parameter. +Returns the [\*fasthttp.Response](https://pkg.go.dev/github.com/valyala/fasthttp#Response) pointer. ```go title="Signature" -func (c fiber.Ctx) Download(file string, filename ...string) error +func (c fiber.Ctx) Response() *fasthttp.Response ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - return c.Download("./files/report-12345.pdf") - // => Download report-12345.pdf - - return c.Download("./files/report-12345.pdf", "report.pdf") - // => Download report.pdf + c.Response().BodyWriter().Write([]byte("Hello, World!")) + // => "Hello, World!" + return nil }) ``` -## Drop +### Reset -Terminates the client connection silently without sending any HTTP headers or response body. +Resets the context fields by the given request when using server handlers. -This can be used for scenarios where you want to block certain requests without notifying the client, such as mitigating -DDoS attacks or protecting sensitive endpoints from unauthorized access. +```go title="Signature" +func (c fiber.Ctx) Reset(fctx *fasthttp.RequestCtx) +``` + +It is used outside of the Fiber Handlers to reset the context for the next request. + +### RestartRouting + +Instead of executing the next method when calling [Next](ctx.md#next), **RestartRouting** restarts execution from the first method that matches the current route. This may be helpful after overriding the path, i.e., an internal redirect. Note that handlers might be executed again, which could result in an infinite loop. ```go title="Signature" -func (c fiber.Ctx) Drop() error +func (c fiber.Ctx) RestartRouting() error ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - if c.IP() == "192.168.1.1" { - return c.Drop() - } +app.Get("/new", func(c fiber.Ctx) error { + return c.SendString("From /new") +}) - return c.SendString("Hello World!") +app.Get("/old", func(c fiber.Ctx) error { + c.Path("/new") + return c.RestartRouting() }) ``` -## End +### Route -End immediately flushes the current response and closes the underlying connection. +Returns the matched [Route](https://pkg.go.dev/github.com/gofiber/fiber?tab=doc#Route) struct. ```go title="Signature" -func (c fiber.Ctx) End() error +func (c fiber.Ctx) Route() *Route ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.SendString("Hello World!") - return c.End() +// http://localhost:8080/hello + +app.Get("/hello/:name", func(c fiber.Ctx) error { + r := c.Route() + fmt.Println(r.Method, r.Path, r.Params, r.Handlers) + // GET /hello/:name handler [name] + + // ... }) ``` :::caution -Calling `c.End()` will disallow further writes to the underlying connection. +Do not rely on `c.Route()` in middlewares **before** calling `c.Next()` - `c.Route()` returns the **last executed route**. ::: -End can be used to stop a middleware from modifying a response of a handler/other middleware down the method chain -when they regain control after calling `c.Next()`. - ```go title="Example" -// Error Logging/Responding middleware -app.Use(func(c fiber.Ctx) error { +func MyMiddleware() fiber.Handler { + return func(c fiber.Ctx) error { + beforeNext := c.Route().Path // Will be '/' err := c.Next() - - // Log errors & write the error to the response - if err != nil { - log.Printf("Got error in middleware: %v", err) - return c.Writef("(got error %v)", err) - } + afterNext := c.Route().Path // Will be '/hello/:name' + return err + } +} +``` - // No errors occured - return nil -}) +### SetContext -// Handler with simulated error +Sets the user-specified implementation for the `context.Context` interface. + +```go title="Signature" +func (c fiber.Ctx) SetContext(ctx context.Context) +``` + +```go title="Example" app.Get("/", func(c fiber.Ctx) error { - // Closes the connection instantly after writing from this handler - // and disallow further modification of its response - defer c.End() + ctx := context.Background() + c.SetContext(ctx) + // Here ctx could be any context implementation - c.SendString("Hello, ... I forgot what comes next!") - return errors.New("some error") + // ... }) ``` -## Format +### String -Performs content-negotiation on the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. It uses [Accepts](ctx.md#accepts) to select a proper format from the supplied offers. A default handler can be provided by setting the `MediaType` to `"default"`. If no offers match and no default is provided, a 406 (Not Acceptable) response is sent. The Content-Type is automatically set when a handler is selected. - -:::info -If the Accept header is **not** specified, the first handler will be used. -::: +Returns a unique string representation of the context. ```go title="Signature" -func (c fiber.Ctx) Format(handlers ...ResFmt) error +func (c fiber.Ctx) String() string ``` ```go title="Example" -// Accept: application/json => {"command":"eat","subject":"fruit"} -// Accept: text/plain => Eat Fruit! -// Accept: application/xml => Not Acceptable -app.Get("/no-default", func(c fiber.Ctx) error { - return c.Format( - fiber.ResFmt{"application/json", func(c fiber.Ctx) error { - return c.JSON(fiber.Map{ - "command": "eat", - "subject": "fruit", - }) - }}, - fiber.ResFmt{"text/plain", func(c fiber.Ctx) error { - return c.SendString("Eat Fruit!") - }}, - ) -}) - -// Accept: application/json => {"command":"eat","subject":"fruit"} -// Accept: text/plain => Eat Fruit! -// Accept: application/xml => Eat Fruit! -app.Get("/default", func(c fiber.Ctx) error { - textHandler := func(c fiber.Ctx) error { - return c.SendString("Eat Fruit!") - } - - handlers := []fiber.ResFmt{ - {"application/json", func(c fiber.Ctx) error { - return c.JSON(fiber.Map{ - "command": "eat", - "subject": "fruit", - }) - }}, - {"text/plain", textHandler}, - {"default", textHandler}, - } +app.Get("/", func(c fiber.Ctx) error { + c.String() // => "#0000000100000001 - 127.0.0.1:3000 <-> 127.0.0.1:61516 - GET http://localhost:3000/" - return c.Format(handlers...) + // ... }) ``` -## FormFile +### ViewBind -MultipartForm files can be retrieved by name, the **first** file from the given key is returned. +Adds variables to the default view variable map binding to the template engine. +Variables are read by the `Render` method and may be overwritten. ```go title="Signature" -func (c fiber.Ctx) FormFile(key string) (*multipart.FileHeader, error) +func (c fiber.Ctx) ViewBind(vars Map) error ``` ```go title="Example" -app.Post("/", func(c fiber.Ctx) error { - // Get first file from form field "document": - file, err := c.FormFile("document") +app.Use(func(c fiber.Ctx) error { + c.ViewBind(fiber.Map{ + "Title": "Hello, World!", + }) + return c.Next() +}) - // Save file to root directory: - return c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)) +app.Get("/", func(c fiber.Ctx) error { + return c.Render("xxx.tmpl", fiber.Map{}) // Render will use the Title variable }) ``` -## FormValue +## Request + +Methods which operate on the incoming request. -Form values can be retrieved by name, the **first** value for the given key is returned. +:::tip +Use `c.Req()` to limit gopls suggestions to only these methods! +::: + +### Accepts + +Checks if the specified **extensions** or **content** **types** are acceptable. + +:::info +Based on the request’s [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. +::: ```go title="Signature" -func (c fiber.Ctx) FormValue(key string, defaultValue ...string) string +func (c fiber.Ctx) Accepts(offers ...string) string +func (c fiber.Ctx) AcceptsCharsets(offers ...string) string +func (c fiber.Ctx) AcceptsEncodings(offers ...string) string +func (c fiber.Ctx) AcceptsLanguages(offers ...string) string ``` ```go title="Example" -app.Post("/", func(c fiber.Ctx) error { - // Get first value from form field "name": - c.FormValue("name") - // => "john" or "" if not exist - - // .. +app.Get("/", func(c fiber.Ctx) error { + c.Accepts("html") // "html" + c.Accepts("text/html") // "text/html" + c.Accepts("json", "text") // "json" + c.Accepts("application/json") // "application/json" + c.Accepts("text/plain", "application/json") // "application/json", due to quality + c.Accepts("image/png") // "" + c.Accepts("png") // "" + // ... }) ``` -:::info +```go title="Example 2" +// Accept: text/html, text/*, application/json, */*; q=0 -Returned value is only valid within the handler. Do not store any references. -Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) +app.Get("/", func(c fiber.Ctx) error { + c.Accepts("text/plain", "application/json") // "application/json", due to specificity + c.Accepts("application/json", "text/html") // "text/html", due to first match + c.Accepts("image/png") // "", due to */* with q=0 is Not Acceptable + // ... +}) +``` -::: +Media-Type parameters are supported. -## Fresh +```go title="Example 3" +// Accept: text/plain, application/json; version=1; foo=bar -When the response is still **fresh** in the client's cache **true** is returned, otherwise **false** is returned to indicate that the client cache is now stale and the full response should be sent. +app.Get("/", func(c fiber.Ctx) error { + // Extra parameters in the accept are ignored + c.Accepts("text/plain;format=flowed") // "text/plain;format=flowed" + + // An offer must contain all parameters present in the Accept type + c.Accepts("application/json") // "" -When a client sends the Cache-Control: no-cache request header to indicate an end-to-end reload request, `Fresh` will return false to make handling these requests transparent. + // Parameter order and capitalization do not matter. Quotes on values are stripped. + c.Accepts(`application/json;foo="bar";VERSION=1`) // "application/json;foo="bar";VERSION=1" +}) +``` -Read more on [https://expressjs.com/en/4x/api.html\#req.fresh](https://expressjs.com/en/4x/api.html#req.fresh) +```go title="Example 4" +// Accept: text/plain;format=flowed;q=0.9, text/plain +// i.e., "I prefer text/plain;format=flowed less than other forms of text/plain" -```go title="Signature" -func (c fiber.Ctx) Fresh() bool +app.Get("/", func(c fiber.Ctx) error { + // Beware: the order in which offers are listed matters. + // Although the client specified they prefer not to receive format=flowed, + // the text/plain Accept matches with "text/plain;format=flowed" first, so it is returned. + c.Accepts("text/plain;format=flowed", "text/plain") // "text/plain;format=flowed" + + // Here, things behave as expected: + c.Accepts("text/plain", "text/plain;format=flowed") // "text/plain" +}) ``` -## Get +Fiber provides similar functions for the other accept headers. -Returns the HTTP request header specified by the field. +```go +// Accept-Charset: utf-8, iso-8859-1;q=0.2 +// Accept-Encoding: gzip, compress;q=0.2 +// Accept-Language: en;q=0.8, nl, ru -:::tip -The match is **case-insensitive**. -::: +app.Get("/", func(c fiber.Ctx) error { + c.AcceptsCharsets("utf-16", "iso-8859-1") + // "iso-8859-1" -```go title="Signature" -func (c fiber.Ctx) Get(key string, defaultValue ...string) string -``` + c.AcceptsEncodings("compress", "br") + // "compress" -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.Get("Content-Type") // "text/plain" - c.Get("CoNtEnT-TypE") // "text/plain" - c.Get("something", "john") // "john" - // .. + c.AcceptsLanguages("pt", "nl", "ru") + // "nl" + // ... }) ``` -:::info -Returned value is only valid within the handler. Do not store any references. -Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) -::: - -## GetReqHeaders +### BaseURL -Returns the HTTP request headers as a map. Since a header can be set multiple times in a single request, the values of the map are slices of strings containing all the different values of the header. +Returns the base URL (**protocol** + **host**) as a `string`. ```go title="Signature" -func (c fiber.Ctx) GetReqHeaders() map[string][]string +func (c fiber.Ctx) BaseURL() string ``` -:::info -Returned value is only valid within the handler. Do not store any references. -Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) -::: +```go title="Example" +// GET https://example.com/page#chapter-1 -## GetRespHeader +app.Get("/", func(c fiber.Ctx) error { + c.BaseURL() // "https://example.com" + // ... +}) +``` -Returns the HTTP response header specified by the field. +### Body -:::tip -The match is **case-insensitive**. -::: +As per the header `Content-Encoding`, this method will try to perform a file decompression from the **body** bytes. In case no `Content-Encoding` header is sent, it will perform as [BodyRaw](#bodyraw). ```go title="Signature" -func (c fiber.Ctx) GetRespHeader(key string, defaultValue ...string) string +func (c fiber.Ctx) Body() []byte ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.GetRespHeader("X-Request-Id") // "8d7ad5e3-aaf3-450b-a241-2beb887efd54" - c.GetRespHeader("Content-Type") // "text/plain" - c.GetRespHeader("something", "john") // "john" - // .. +// echo 'user=john' | gzip | curl -v -i --data-binary @- -H "Content-Encoding: gzip" http://localhost:8080 + +app.Post("/", func(c fiber.Ctx) error { + // Decompress body from POST request based on the Content-Encoding and return the raw content: + return c.Send(c.Body()) // []byte("user=john") }) ``` @@ -705,12 +563,21 @@ Returned value is only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) ::: -## GetRespHeaders +### BodyRaw -Returns the HTTP response headers as a map. Since a header can be set multiple times in a single request, the values of the map are slices of strings containing all the different values of the header. +Returns the raw request **body**. ```go title="Signature" -func (c fiber.Ctx) GetRespHeaders() map[string][]string +func (c fiber.Ctx) BodyRaw() []byte +``` + +```go title="Example" +// curl -X POST http://localhost:8080 -d user=john + +app.Post("/", func(c fiber.Ctx) error { + // Get raw body from POST request: + return c.Send(c.BodyRaw()) // []byte("user=john") +}) ``` :::info @@ -718,48 +585,36 @@ Returned value is only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) ::: -## GetRouteURL +### ClientHelloInfo -Generates URLs to named routes, with parameters. URLs are relative, for example: "/user/1831" +`ClientHelloInfo` contains information from a ClientHello message in order to guide application logic in the `GetCertificate` and `GetConfigForClient` callbacks. +You can refer to the [ClientHelloInfo](https://golang.org/pkg/crypto/tls/#ClientHelloInfo) struct documentation for more information on the returned struct. ```go title="Signature" -func (c fiber.Ctx) GetRouteURL(routeName string, params Map) (string, error) +func (c fiber.Ctx) ClientHelloInfo() *tls.ClientHelloInfo ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - return c.SendString("Home page") -}).Name("home") - -app.Get("/user/:id", func(c fiber.Ctx) error { - return c.SendString(c.Params("id")) -}).Name("user.show") - -app.Get("/test", func(c fiber.Ctx) error { - location, _ := c.GetRouteURL("user.show", fiber.Map{"id": 1}) - return c.SendString(location) +// GET http://example.com/hello +app.Get("/hello", func(c fiber.Ctx) error { + chi := c.ClientHelloInfo() + // ... }) - -// /test returns "/user/1" ``` -## Host - -Returns the host derived from the [Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) HTTP header. +### Cookies -In a network context, [`Host`](#host) refers to the combination of a hostname and potentially a port number used for connecting, while [`Hostname`](#hostname) refers specifically to the name assigned to a device on a network, excluding any port information. +Gets a cookie value by key. You can pass an optional default value that will be returned if the cookie key does not exist. ```go title="Signature" -func (c fiber.Ctx) Host() string +func (c fiber.Ctx) Cookies(key string, defaultValue ...string) string ``` ```go title="Example" -// GET http://google.com:8080/search - app.Get("/", func(c fiber.Ctx) error { - c.Host() // "google.com:8080" - c.Hostname() // "google.com" - + // Get cookie by key: + c.Cookies("name") // "john" + c.Cookies("empty", "doe") // "doe" // ... }) ``` @@ -769,30 +624,137 @@ Returned value is only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) ::: -## Hostname +### FormFile -Returns the hostname derived from the [Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) HTTP header. +MultipartForm files can be retrieved by name, the **first** file from the given key is returned. ```go title="Signature" -func (c fiber.Ctx) Hostname() string +func (c fiber.Ctx) FormFile(key string) (*multipart.FileHeader, error) ``` ```go title="Example" -// GET http://google.com/search - -app.Get("/", func(c fiber.Ctx) error { - c.Hostname() // "google.com" +app.Post("/", func(c fiber.Ctx) error { + // Get first file from form field "document": + file, err := c.FormFile("document") - // ... + // Save file to root directory: + return c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)) }) ``` -:::info -Returned value is only valid within the handler. Do not store any references. +### FormValue + +Form values can be retrieved by name, the **first** value for the given key is returned. + +```go title="Signature" +func (c fiber.Ctx) FormValue(key string, defaultValue ...string) string +``` + +```go title="Example" +app.Post("/", func(c fiber.Ctx) error { + // Get first value from form field "name": + c.FormValue("name") + // => "john" or "" if not exist + + // .. +}) +``` + +:::info + +Returned value is only valid within the handler. Do not store any references. +Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) + +::: + +### Fresh + +When the response is still **fresh** in the client's cache **true** is returned, otherwise **false** is returned to indicate that the client cache is now stale and the full response should be sent. + +When a client sends the Cache-Control: no-cache request header to indicate an end-to-end reload request, `Fresh` will return false to make handling these requests transparent. + +Read more on [https://expressjs.com/en/4x/api.html\#req.fresh](https://expressjs.com/en/4x/api.html#req.fresh) + +```go title="Signature" +func (c fiber.Ctx) Fresh() bool +``` + +### Get + +Returns the HTTP request header specified by the field. + +:::tip +The match is **case-insensitive**. +::: + +```go title="Signature" +func (c fiber.Ctx) Get(key string, defaultValue ...string) string +``` + +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + c.Get("Content-Type") // "text/plain" + c.Get("CoNtEnT-TypE") // "text/plain" + c.Get("something", "john") // "john" + // .. +}) +``` + +:::info +Returned value is only valid within the handler. Do not store any references. +Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) +::: + +### Host + +Returns the host derived from the [Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) HTTP header. + +In a network context, [`Host`](#host) refers to the combination of a hostname and potentially a port number used for connecting, while [`Hostname`](#hostname) refers specifically to the name assigned to a device on a network, excluding any port information. + +```go title="Signature" +func (c fiber.Ctx) Host() string +``` + +```go title="Example" +// GET http://google.com:8080/search + +app.Get("/", func(c fiber.Ctx) error { + c.Host() // "google.com:8080" + c.Hostname() // "google.com" + + // ... +}) +``` + +:::info +Returned value is only valid within the handler. Do not store any references. +Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) +::: + +### Hostname + +Returns the hostname derived from the [Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) HTTP header. + +```go title="Signature" +func (c fiber.Ctx) Hostname() string +``` + +```go title="Example" +// GET http://google.com/search + +app.Get("/", func(c fiber.Ctx) error { + c.Hostname() // "google.com" + + // ... +}) +``` + +:::info +Returned value is only valid within the handler. Do not store any references. Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) ::: -## IP +### IP Returns the remote IP address of the request. @@ -816,7 +778,7 @@ app := fiber.New(fiber.Config{ }) ``` -## IPs +### IPs Returns an array of IP addresses specified in the [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) request header. @@ -838,7 +800,7 @@ app.Get("/", func(c fiber.Ctx) error { Improper use of the X-Forwarded-For header can be a security risk. For details, see the [Security and privacy concerns](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#security_and_privacy_concerns) section. ::: -## Is +### Is Returns the matching **content type**, if the incoming request’s [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) HTTP header field matches the [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) specified by the type parameter. @@ -862,7 +824,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## IsFromLocal +### IsFromLocal Returns `true` if the request came from localhost. @@ -879,7 +841,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## IsProxyTrusted +### IsProxyTrusted Checks the trustworthiness of the remote IP. If [`TrustProxy`](fiber.md#trustproxy) is `false`, it returns `true`. @@ -908,356 +870,98 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## JSON +### Method -Converts any **interface** or **string** to JSON using the [encoding/json](https://pkg.go.dev/encoding/json) package. - -:::info -JSON also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/json`. -::: +Returns a string corresponding to the HTTP method of the request: `GET`, `POST`, `PUT`, and so on. +Optionally, you can override the method by passing a string. ```go title="Signature" -func (c fiber.Ctx) JSON(data any, ctype ...string) error +func (c fiber.Ctx) Method(override ...string) string ``` ```go title="Example" -type SomeStruct struct { - Name string - Age uint8 -} - -app.Get("/json", func(c fiber.Ctx) error { - // Create data struct: - data := SomeStruct{ - Name: "Grame", - Age: 20, - } - - return c.JSON(data) - // => Content-Type: application/json - // => {"Name": "Grame", "Age": 20} +app.Post("/override", func(c fiber.Ctx) error { + c.Method() // "POST" - return c.JSON(fiber.Map{ - "name": "Grame", - "age": 20, - }) - // => Content-Type: application/json - // => {"name": "Grame", "age": 20} + c.Method("GET") + c.Method() // "GET" - return c.JSON(fiber.Map{ - "type": "https://example.com/probs/out-of-credit", - "title": "You do not have enough credit.", - "status": 403, - "detail": "Your current balance is 30, but that costs 50.", - "instance": "/account/12345/msgs/abc", - }, "application/problem+json") - // => Content-Type: application/problem+json - // => "{ - // => "type": "https://example.com/probs/out-of-credit", - // => "title": "You do not have enough credit.", - // => "status": 403, - // => "detail": "Your current balance is 30, but that costs 50.", - // => "instance": "/account/12345/msgs/abc", - // => }" + // ... }) ``` -## JSONP - -Sends a JSON response with JSONP support. This method is identical to [JSON](ctx.md#json), except that it opts-in to JSONP callback support. By default, the callback name is simply `callback`. +### MultipartForm -Override this by passing a **named string** in the method. +To access multipart form entries, you can parse the binary with `MultipartForm()`. This returns a `*multipart.Form`, allowing you to access form values and files. ```go title="Signature" -func (c fiber.Ctx) JSONP(data any, callback ...string) error +func (c fiber.Ctx) MultipartForm() (*multipart.Form, error) ``` ```go title="Example" -type SomeStruct struct { - Name string - Age uint8 -} +app.Post("/", func(c fiber.Ctx) error { + // Parse the multipart form: + if form, err := c.MultipartForm(); err == nil { + // => *multipart.Form -app.Get("/", func(c fiber.Ctx) error { - // Create data struct: - data := SomeStruct{ - Name: "Grame", - Age: 20, - } + if token := form.Value["token"]; len(token) > 0 { + // Get key value: + fmt.Println(token[0]) + } - return c.JSONP(data) - // => callback({"Name": "Grame", "Age": 20}) + // Get all files from "documents" key: + files := form.File["documents"] + // => []*multipart.FileHeader - return c.JSONP(data, "customFunc") - // => customFunc({"Name": "Grame", "Age": 20}) + // Loop through files: + for _, file := range files { + fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0]) + // => "tutorial.pdf" 360641 "application/pdf" + + // Save the files to disk: + if err := c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)); err != nil { + return err + } + } + } + + return nil }) ``` -## CBOR - -CBOR converts any interface or string to CBOR encoded bytes. +### OriginalURL -:::info -CBOR also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/cbor`. -::: +Returns the original request URL. ```go title="Signature" -func (c fiber.Ctx) CBOR(data any, ctype ...string) error +func (c fiber.Ctx) OriginalURL() string ``` ```go title="Example" -type SomeStruct struct { - Name string `cbor:"name"` - Age uint8 `cbor:"age"` -} - -app.Get("/cbor", func(c fiber.Ctx) error { - // Create data struct: - data := SomeStruct{ - Name: "Grame", - Age: 20, - } - - return c.CBOR(data) - // => Content-Type: application/cbor - // => \xa2dnameeGramecage\x14 +// GET http://example.com/search?q=something - return c.CBOR(fiber.Map{ - "name": "Grame", - "age": 20, - }) - // => Content-Type: application/cbor - // => \xa2dnameeGramecage\x14 +app.Get("/", func(c fiber.Ctx) error { + c.OriginalURL() // "/search?q=something" - return c.CBOR(fiber.Map{ - "type": "https://example.com/probs/out-of-credit", - "title": "You do not have enough credit.", - "status": 403, - "detail": "Your current balance is 30, but that costs 50.", - "instance": "/account/12345/msgs/abc", - }) - // => Content-Type: application/cbor - // => \xa5dtypex'https://example.com/probs/out-of-creditetitlex\x1eYou do not have enough credit.fstatus\x19\x01\x93fdetailx.Your current balance is 30, but that costs 50.hinstancew/account/12345/msgs/abc + // ... }) ``` -## Links +:::info +Returned value is only valid within the handler. Do not store any references. +Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) +::: -Joins the links followed by the property to populate the response’s [Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) HTTP header field. +### Params + +This method can be used to get the route parameters. You can pass an optional default value that will be returned if the param key does not exist. + +:::info +Defaults to an empty string \(`""`\) if the param **doesn't** exist. +::: ```go title="Signature" -func (c fiber.Ctx) Links(link ...string) -``` - -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.Links( - "http://api.example.com/users?page=2", "next", - "http://api.example.com/users?page=5", "last", - ) - // Link: ; rel="next", - // ; rel="last" - - // ... -}) -``` - -## Locals - -A method that stores variables scoped to the request and, therefore, are available only to the routes that match the request. The stored variables are removed after the request is handled. If any of the stored data implements the `io.Closer` interface, its `Close` method will be called before it's removed. - -:::tip -This is useful if you want to pass some **specific** data to the next middleware. Remember to perform type assertions when retrieving the data to ensure it is of the expected type. You can also use a non-exported type as a key to avoid collisions. -::: - -```go title="Signature" -func (c fiber.Ctx) Locals(key any, value ...any) any -``` - -```go title="Example" - -// keyType is an unexported type for keys defined in this package. -// This prevents collisions with keys defined in other packages. -type keyType int - -// userKey is the key for user.User values in Contexts. It is -// unexported; clients use user.NewContext and user.FromContext -// instead of using this key directly. -var userKey keyType - -app.Use(func(c fiber.Ctx) error { - c.Locals(userKey, "admin") // Stores the string "admin" under a non-exported type key - return c.Next() -}) - -app.Get("/admin", func(c fiber.Ctx) error { - user, ok := c.Locals(userKey).(string) // Retrieves the data stored under the key and performs a type assertion - if ok && user == "admin" { - return c.Status(fiber.StatusOK).SendString("Welcome, admin!") - } - return c.SendStatus(fiber.StatusForbidden) -}) -``` - -An alternative version of the `Locals` method that takes advantage of Go's generics feature is also available. This version allows for the manipulation and retrieval of local values within a request's context with a more specific data type. - -```go title="Signature" -func Locals[V any](c fiber.Ctx, key any, value ...V) V -``` - -```go title="Example" -app.Use(func(c fiber.Ctx) error { - fiber.Locals[string](c, "john", "doe") - fiber.Locals[int](c, "age", 18) - fiber.Locals[bool](c, "isHuman", true) - return c.Next() -}) - -app.Get("/test", func(c fiber.Ctx) error { - fiber.Locals[string](c, "john") // "doe" - fiber.Locals[int](c, "age") // 18 - fiber.Locals[bool](c, "isHuman") // true - return nil -}) -```` - -Make sure to understand and correctly implement the `Locals` method in both its standard and generic form for better control over route-specific data within your application. - -## Location - -Sets the response [Location](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location) HTTP header to the specified path parameter. - -```go title="Signature" -func (c fiber.Ctx) Location(path string) -``` - -```go title="Example" -app.Post("/", func(c fiber.Ctx) error { - c.Location("http://example.com") - - c.Location("/foo/bar") - - return nil -}) -``` - -## Method - -Returns a string corresponding to the HTTP method of the request: `GET`, `POST`, `PUT`, and so on. -Optionally, you can override the method by passing a string. - -```go title="Signature" -func (c fiber.Ctx) Method(override ...string) string -``` - -```go title="Example" -app.Post("/override", func(c fiber.Ctx) error { - c.Method() // "POST" - - c.Method("GET") - c.Method() // "GET" - - // ... -}) -``` - -## MultipartForm - -To access multipart form entries, you can parse the binary with `MultipartForm()`. This returns a `*multipart.Form`, allowing you to access form values and files. - -```go title="Signature" -func (c fiber.Ctx) MultipartForm() (*multipart.Form, error) -``` - -```go title="Example" -app.Post("/", func(c fiber.Ctx) error { - // Parse the multipart form: - if form, err := c.MultipartForm(); err == nil { - // => *multipart.Form - - if token := form.Value["token"]; len(token) > 0 { - // Get key value: - fmt.Println(token[0]) - } - - // Get all files from "documents" key: - files := form.File["documents"] - // => []*multipart.FileHeader - - // Loop through files: - for _, file := range files { - fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0]) - // => "tutorial.pdf" 360641 "application/pdf" - - // Save the files to disk: - if err := c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)); err != nil { - return err - } - } - } - - return nil -}) -``` - -## Next - -When **Next** is called, it executes the next method in the stack that matches the current route. You can pass an error struct within the method that will end the chaining and call the [error handler](https://docs.gofiber.io/guide/error-handling). - -```go title="Signature" -func (c fiber.Ctx) Next() error -``` - -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - fmt.Println("1st route!") - return c.Next() -}) - -app.Get("*", func(c fiber.Ctx) error { - fmt.Println("2nd route!") - return c.Next() -}) - -app.Get("/", func(c fiber.Ctx) error { - fmt.Println("3rd route!") - return c.SendString("Hello, World!") -}) -``` - -## OriginalURL - -Returns the original request URL. - -```go title="Signature" -func (c fiber.Ctx) OriginalURL() string -``` - -```go title="Example" -// GET http://example.com/search?q=something - -app.Get("/", func(c fiber.Ctx) error { - c.OriginalURL() // "/search?q=something" - - // ... -}) -``` - -:::info -Returned value is only valid within the handler. Do not store any references. -Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation) -::: - -## Params - -This method can be used to get the route parameters. You can pass an optional default value that will be returned if the param key does not exist. - -:::info -Defaults to an empty string \(`""`\) if the param **doesn't** exist. -::: - -```go title="Signature" -func (c fiber.Ctx) Params(key string, defaultValue ...string) string +func (c fiber.Ctx) Params(key string, defaultValue ...string) string ``` ```go title="Example" @@ -1326,7 +1030,7 @@ The generic `Params` function supports returning the following data types based - String: `string` - Byte array: `[]byte` -## Path +### Path Contains the path part of the request URL. Optionally, you can override the path by passing a string. For internal redirects, you might want to call [RestartRouting](ctx.md#restartrouting) instead of [Next](ctx.md#next). @@ -1347,7 +1051,7 @@ app.Get("/users", func(c fiber.Ctx) error { }) ``` -## Port +### Port Returns the remote port of the request. @@ -1365,7 +1069,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## Protocol +### Protocol Contains the request protocol string: `http` or `https` for **TLS** requests. @@ -1383,7 +1087,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## Queries +### Queries `Queries` is a function that returns an object containing a property for each query string parameter in the route. @@ -1447,7 +1151,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## Query +### Query This method returns a string corresponding to a query string parameter by name. You can pass an optional default value that will be returned if the query key does not exist. @@ -1508,7 +1212,7 @@ The generic `Query` function supports returning the following data types based o - String: `string` - Byte array: `[]byte` -## Range +### Range Returns a struct containing the type and a slice of ranges. @@ -1529,245 +1233,660 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## Redirect - -Returns the Redirect reference. +### SaveFile -For detailed information, check the [Redirect](./redirect.md) documentation. +Method is used to save **any** multipart file to disk. ```go title="Signature" -func (c fiber.Ctx) Redirect() *Redirect +func (c fiber.Ctx) SaveFile(fh *multipart.FileHeader, path string) error ``` ```go title="Example" -app.Get("/coffee", func(c fiber.Ctx) error { - return c.Redirect().To("/teapot") -}) - -app.Get("/teapot", func(c fiber.Ctx) error { - return c.Status(fiber.StatusTeapot).Send("🍵 short and stout 🍵") -}) -``` +app.Post("/", func(c fiber.Ctx) error { + // Parse the multipart form: + if form, err := c.MultipartForm(); err == nil { + // => *multipart.Form -## Render + // Get all files from "documents" key: + files := form.File["documents"] + // => []*multipart.FileHeader -Renders a view with data and sends a `text/html` response. By default, `Render` uses the default [**Go Template engine**](https://pkg.go.dev/html/template/). If you want to use another view engine, please take a look at our [**Template middleware**](https://docs.gofiber.io/template). + // Loop through files: + for _, file := range files { + fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0]) + // => "tutorial.pdf" 360641 "application/pdf" -```go title="Signature" -func (c fiber.Ctx) Render(name string, bind any, layouts ...string) error + // Save the files to disk: + if err := c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)); err != nil { + return err + } + } + return err + } +}) ``` -## Request +### SaveFileToStorage -Returns the [*fasthttp.Request](https://pkg.go.dev/github.com/valyala/fasthttp#Request) pointer. +Method is used to save **any** multipart file to an external storage system. ```go title="Signature" -func (c fiber.Ctx) Request() *fasthttp.Request +func (c fiber.Ctx) SaveFileToStorage(fileheader *multipart.FileHeader, path string, storage Storage) error ``` ```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.Request().Header.Method() - // => []byte("GET") -}) -``` +storage := memory.New() -## RequestCtx +app.Post("/", func(c fiber.Ctx) error { + // Parse the multipart form: + if form, err := c.MultipartForm(); err == nil { + // => *multipart.Form -Returns [\*fasthttp.RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) that is compatible with the `context.Context` interface that requires a deadline, a cancellation signal, and other values across API boundaries. + // Get all files from "documents" key: + files := form.File["documents"] + // => []*multipart.FileHeader -```go title="Signature" -func (c fiber.Ctx) RequestCtx() *fasthttp.RequestCtx + // Loop through files: + for _, file := range files { + fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0]) + // => "tutorial.pdf" 360641 "application/pdf" + + // Save the files to storage: + if err := c.SaveFileToStorage(file, fmt.Sprintf("./%s", file.Filename), storage); err != nil { + return err + } + } + return err + } +}) ``` +### Schema + +Contains the request protocol string: `http` or `https` for TLS requests. + :::info -Please read the [Fasthttp Documentation](https://pkg.go.dev/github.com/valyala/fasthttp?tab=doc) for more information. +Please use [`Config.TrustProxy`](fiber.md#trustproxy) to prevent header spoofing if your app is behind a proxy. ::: +```go title="Signature" +func (c fiber.Ctx) Schema() string +``` + +```go title="Example" +// GET http://example.com + +app.Get("/", func(c fiber.Ctx) error { + c.Schema() // "http" + + // ... +}) +``` + +### Secure + +A boolean property that is `true` if a **TLS** connection is established. + +```go title="Signature" +func (c fiber.Ctx) Secure() bool +``` + +```go title="Example" +// Secure() method is equivalent to: +c.Protocol() == "https" +``` + +### Stale + +[https://expressjs.com/en/4x/api.html#req.stale](https://expressjs.com/en/4x/api.html#req.stale) + +```go title="Signature" +func (c fiber.Ctx) Stale() bool +``` + +### Subdomains + +Returns a slice of subdomains in the domain name of the request. + +The application property `subdomain offset`, which defaults to `2`, is used for determining the beginning of the subdomain segments. + +```go title="Signature" +func (c fiber.Ctx) Subdomains(offset ...int) []string +``` + +```go title="Example" +// Host: "tobi.ferrets.example.com" + +app.Get("/", func(c fiber.Ctx) error { + c.Subdomains() // ["ferrets", "tobi"] + c.Subdomains(1) // ["tobi"] + + // ... +}) +``` + +### XHR + +A boolean property that is `true` if the request’s [X-Requested-With](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) header field is [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest), indicating that the request was issued by a client library (such as [jQuery](https://api.jquery.com/jQuery.ajax/)). + +```go title="Signature" +func (c fiber.Ctx) XHR() bool +``` + +```go title="Example" +// X-Requested-With: XMLHttpRequest + +app.Get("/", func(c fiber.Ctx) error { + c.XHR() // true + + // ... +}) +``` + ## Response -Returns the [\*fasthttp.Response](https://pkg.go.dev/github.com/valyala/fasthttp#Response) pointer. +Methods which modify the response object. + +:::tip +Use `c.Res()` to limit gopls suggestions to only these methods! +::: + +### Append + +Appends the specified **value** to the HTTP response header field. + +:::caution +If the header is **not** already set, it creates the header with the specified value. +::: ```go title="Signature" -func (c fiber.Ctx) Response() *fasthttp.Response +func (c fiber.Ctx) Append(field string, values ...string) ``` ```go title="Example" app.Get("/", func(c fiber.Ctx) error { - c.Response().BodyWriter().Write([]byte("Hello, World!")) - // => "Hello, World!" - return nil + c.Append("Link", "http://google.com", "http://localhost") + // => Link: http://google.com, http://localhost + + c.Append("Link", "Test") + // => Link: http://google.com, http://localhost, Test + + // ... }) ``` -## Reset +### Attachment -Resets the context fields by the given request when using server handlers. +Sets the HTTP response [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header field to `attachment`. ```go title="Signature" -func (c fiber.Ctx) Reset(fctx *fasthttp.RequestCtx) +func (c fiber.Ctx) Attachment(filename ...string) ``` -It is used outside of the Fiber Handlers to reset the context for the next request. +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + c.Attachment() + // => Content-Disposition: attachment + + c.Attachment("./upload/images/logo.png") + // => Content-Disposition: attachment; filename="logo.png" + // => Content-Type: image/png -## RestartRouting + // ... +}) +``` -Instead of executing the next method when calling [Next](ctx.md#next), **RestartRouting** restarts execution from the first method that matches the current route. This may be helpful after overriding the path, i.e., an internal redirect. Note that handlers might be executed again, which could result in an infinite loop. +### AutoFormat + +Performs content-negotiation on the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. It uses [Accepts](ctx.md#accepts) to select a proper format. +The supported content types are `text/html`, `text/plain`, `application/json`, and `application/xml`. +For more flexible content negotiation, use [Format](ctx.md#format). + +:::info +If the header is **not** specified or there is **no** proper format, **text/plain** is used. +::: ```go title="Signature" -func (c fiber.Ctx) RestartRouting() error +func (c fiber.Ctx) AutoFormat(body any) error ``` ```go title="Example" -app.Get("/new", func(c fiber.Ctx) error { - return c.SendString("From /new") +app.Get("/", func(c fiber.Ctx) error { + // Accept: text/plain + c.AutoFormat("Hello, World!") + // => Hello, World! + + // Accept: text/html + c.AutoFormat("Hello, World!") + // =>

Hello, World!

+ + type User struct { + Name string + } + user := User{"John Doe"} + + // Accept: application/json + c.AutoFormat(user) + // => {"Name":"John Doe"} + + // Accept: application/xml + c.AutoFormat(user) + // => John Doe + // .. }) +``` -app.Get("/old", func(c fiber.Ctx) error { - c.Path("/new") - return c.RestartRouting() +### ClearCookie + +Expires a client cookie (or all cookies if left empty). + +```go title="Signature" +func (c fiber.Ctx) ClearCookie(key ...string) +``` + +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + // Clears all cookies: + c.ClearCookie() + + // Expire specific cookie by name: + c.ClearCookie("user") + + // Expire multiple cookies by names: + c.ClearCookie("token", "session", "track_id", "version") + // ... +}) +``` + +:::caution +Web browsers and other compliant clients will only clear the cookie if the given options are identical to those when creating the cookie, excluding `Expires` and `MaxAge`. `ClearCookie` will not set these values for you - a technique similar to the one shown below should be used to ensure your cookie is deleted. +::: + +```go title="Example" +app.Get("/set", func(c fiber.Ctx) error { + c.Cookie(&fiber.Cookie{ + Name: "token", + Value: "randomvalue", + Expires: time.Now().Add(24 * time.Hour), + HTTPOnly: true, + SameSite: "lax", + }) + + // ... +}) + +app.Get("/delete", func(c fiber.Ctx) error { + c.Cookie(&fiber.Cookie{ + Name: "token", + // Set expiry date to the past + Expires: time.Now().Add(-(time.Hour * 2)), + HTTPOnly: true, + SameSite: "lax", + }) + + // ... +}) +``` + +### Cookie + +Sets a cookie. + +```go title="Signature" +func (c fiber.Ctx) Cookie(cookie *Cookie) +``` + +```go +type Cookie struct { + Name string `json:"name"` // The name of the cookie + Value string `json:"value"` // The value of the cookie + Path string `json:"path"` // Specifies a URL path which is allowed to receive the cookie + Domain string `json:"domain"` // Specifies the domain which is allowed to receive the cookie + MaxAge int `json:"max_age"` // The maximum age (in seconds) of the cookie + Expires time.Time `json:"expires"` // The expiration date of the cookie + Secure bool `json:"secure"` // Indicates that the cookie should only be transmitted over a secure HTTPS connection + HTTPOnly bool `json:"http_only"` // Indicates that the cookie is accessible only through the HTTP protocol + SameSite string `json:"same_site"` // Controls whether or not a cookie is sent with cross-site requests + Partitioned bool `json:"partitioned"` // Indicates if the cookie is stored in a partitioned cookie jar + SessionOnly bool `json:"session_only"` // Indicates if the cookie is a session-only cookie +} +``` + +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + // Create cookie + cookie := new(fiber.Cookie) + cookie.Name = "john" + cookie.Value = "doe" + cookie.Expires = time.Now().Add(24 * time.Hour) + + // Set cookie + c.Cookie(cookie) + // ... +}) +``` + +:::info +Partitioned cookies allow partitioning the cookie jar by top-level site, enhancing user privacy by preventing cookies from being shared across different sites. This feature is particularly useful in scenarios where a user interacts with embedded third-party services that should not have access to the main site's cookies. You can check out [CHIPS](https://developers.google.com/privacy-sandbox/3pcd/chips) for more information. +::: + +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + // Create a new partitioned cookie + cookie := new(fiber.Cookie) + cookie.Name = "user_session" + cookie.Value = "abc123" + cookie.Partitioned = true // This cookie will be stored in a separate jar when it's embedded into another website + + // Set the cookie in the response + c.Cookie(cookie) + return c.SendString("Partitioned cookie set") +}) +``` + +### Download + +Transfers the file from the given path as an `attachment`. + +Typically, browsers will prompt the user to download. By default, the [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header `filename=` parameter is the file path (_this typically appears in the browser dialog_). +Override this default with the **filename** parameter. + +```go title="Signature" +func (c fiber.Ctx) Download(file string, filename ...string) error +``` + +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + return c.Download("./files/report-12345.pdf") + // => Download report-12345.pdf + + return c.Download("./files/report-12345.pdf", "report.pdf") + // => Download report.pdf +}) +``` + +### End + +End immediately flushes the current response and closes the underlying connection. + +```go title="Signature" +func (c fiber.Ctx) End() error +``` + +```go title="Example" +app.Get("/", func(c fiber.Ctx) error { + c.SendString("Hello World!") + return c.End() +}) +``` + +:::caution +Calling `c.End()` will disallow further writes to the underlying connection. +::: + +End can be used to stop a middleware from modifying a response of a handler/other middleware down the method chain +when they regain control after calling `c.Next()`. + +```go title="Example" +// Error Logging/Responding middleware +app.Use(func(c fiber.Ctx) error { + err := c.Next() + + // Log errors & write the error to the response + if err != nil { + log.Printf("Got error in middleware: %v", err) + return c.Writef("(got error %v)", err) + } + + // No errors occured + return nil +}) + +// Handler with simulated error +app.Get("/", func(c fiber.Ctx) error { + // Closes the connection instantly after writing from this handler + // and disallow further modification of its response + defer c.End() + + c.SendString("Hello, ... I forgot what comes next!") + return errors.New("some error") +}) +``` + +### Format + +Performs content-negotiation on the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. It uses [Accepts](ctx.md#accepts) to select a proper format from the supplied offers. A default handler can be provided by setting the `MediaType` to `"default"`. If no offers match and no default is provided, a 406 (Not Acceptable) response is sent. The Content-Type is automatically set when a handler is selected. + +:::info +If the Accept header is **not** specified, the first handler will be used. +::: + +```go title="Signature" +func (c fiber.Ctx) Format(handlers ...ResFmt) error +``` + +```go title="Example" +// Accept: application/json => {"command":"eat","subject":"fruit"} +// Accept: text/plain => Eat Fruit! +// Accept: application/xml => Not Acceptable +app.Get("/no-default", func(c fiber.Ctx) error { + return c.Format( + fiber.ResFmt{"application/json", func(c fiber.Ctx) error { + return c.JSON(fiber.Map{ + "command": "eat", + "subject": "fruit", + }) + }}, + fiber.ResFmt{"text/plain", func(c fiber.Ctx) error { + return c.SendString("Eat Fruit!") + }}, + ) +}) + +// Accept: application/json => {"command":"eat","subject":"fruit"} +// Accept: text/plain => Eat Fruit! +// Accept: application/xml => Eat Fruit! +app.Get("/default", func(c fiber.Ctx) error { + textHandler := func(c fiber.Ctx) error { + return c.SendString("Eat Fruit!") + } + + handlers := []fiber.ResFmt{ + {"application/json", func(c fiber.Ctx) error { + return c.JSON(fiber.Map{ + "command": "eat", + "subject": "fruit", + }) + }}, + {"text/plain", textHandler}, + {"default", textHandler}, + } + + return c.Format(handlers...) +}) +``` + +### JSON + +Converts any **interface** or **string** to JSON using the [encoding/json](https://pkg.go.dev/encoding/json) package. + +:::info +JSON also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/json`. +::: + +```go title="Signature" +func (c fiber.Ctx) JSON(data any, ctype ...string) error +``` + +```go title="Example" +type SomeStruct struct { + Name string + Age uint8 +} + +app.Get("/json", func(c fiber.Ctx) error { + // Create data struct: + data := SomeStruct{ + Name: "Grame", + Age: 20, + } + + return c.JSON(data) + // => Content-Type: application/json + // => {"Name": "Grame", "Age": 20} + + return c.JSON(fiber.Map{ + "name": "Grame", + "age": 20, + }) + // => Content-Type: application/json + // => {"name": "Grame", "age": 20} + + return c.JSON(fiber.Map{ + "type": "https://example.com/probs/out-of-credit", + "title": "You do not have enough credit.", + "status": 403, + "detail": "Your current balance is 30, but that costs 50.", + "instance": "/account/12345/msgs/abc", + }, "application/problem+json") + // => Content-Type: application/problem+json + // => "{ + // => "type": "https://example.com/probs/out-of-credit", + // => "title": "You do not have enough credit.", + // => "status": 403, + // => "detail": "Your current balance is 30, but that costs 50.", + // => "instance": "/account/12345/msgs/abc", + // => }" }) ``` -## Route +### JSONP -Returns the matched [Route](https://pkg.go.dev/github.com/gofiber/fiber?tab=doc#Route) struct. +Sends a JSON response with JSONP support. This method is identical to [JSON](ctx.md#json), except that it opts-in to JSONP callback support. By default, the callback name is simply `callback`. + +Override this by passing a **named string** in the method. ```go title="Signature" -func (c fiber.Ctx) Route() *Route +func (c fiber.Ctx) JSONP(data any, callback ...string) error ``` ```go title="Example" -// http://localhost:8080/hello +type SomeStruct struct { + Name string + Age uint8 +} -app.Get("/hello/:name", func(c fiber.Ctx) error { - r := c.Route() - fmt.Println(r.Method, r.Path, r.Params, r.Handlers) - // GET /hello/:name handler [name] +app.Get("/", func(c fiber.Ctx) error { + // Create data struct: + data := SomeStruct{ + Name: "Grame", + Age: 20, + } - // ... + return c.JSONP(data) + // => callback({"Name": "Grame", "Age": 20}) + + return c.JSONP(data, "customFunc") + // => customFunc({"Name": "Grame", "Age": 20}) }) ``` -:::caution -Do not rely on `c.Route()` in middlewares **before** calling `c.Next()` - `c.Route()` returns the **last executed route**. -::: - -```go title="Example" -func MyMiddleware() fiber.Handler { - return func(c fiber.Ctx) error { - beforeNext := c.Route().Path // Will be '/' - err := c.Next() - afterNext := c.Route().Path // Will be '/hello/:name' - return err - } -} -``` +### CBOR -## SaveFile +CBOR converts any interface or string to CBOR encoded bytes. -Method is used to save **any** multipart file to disk. +:::info +CBOR also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/cbor`. +::: ```go title="Signature" -func (c fiber.Ctx) SaveFile(fh *multipart.FileHeader, path string) error +func (c fiber.Ctx) CBOR(data any, ctype ...string) error ``` ```go title="Example" -app.Post("/", func(c fiber.Ctx) error { - // Parse the multipart form: - if form, err := c.MultipartForm(); err == nil { - // => *multipart.Form +type SomeStruct struct { + Name string `cbor:"name"` + Age uint8 `cbor:"age"` +} - // Get all files from "documents" key: - files := form.File["documents"] - // => []*multipart.FileHeader +app.Get("/cbor", func(c fiber.Ctx) error { + // Create data struct: + data := SomeStruct{ + Name: "Grame", + Age: 20, + } - // Loop through files: - for _, file := range files { - fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0]) - // => "tutorial.pdf" 360641 "application/pdf" + return c.CBOR(data) + // => Content-Type: application/cbor + // => \xa2dnameeGramecage\x14 - // Save the files to disk: - if err := c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)); err != nil { - return err - } - } - return err - } + return c.CBOR(fiber.Map{ + "name": "Grame", + "age": 20, + }) + // => Content-Type: application/cbor + // => \xa2dnameeGramecage\x14 + + return c.CBOR(fiber.Map{ + "type": "https://example.com/probs/out-of-credit", + "title": "You do not have enough credit.", + "status": 403, + "detail": "Your current balance is 30, but that costs 50.", + "instance": "/account/12345/msgs/abc", + }) + // => Content-Type: application/cbor + // => \xa5dtypex'https://example.com/probs/out-of-creditetitlex\x1eYou do not have enough credit.fstatus\x19\x01\x93fdetailx.Your current balance is 30, but that costs 50.hinstancew/account/12345/msgs/abc }) ``` -## SaveFileToStorage +### Links -Method is used to save **any** multipart file to an external storage system. +Joins the links followed by the property to populate the response’s [Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) HTTP header field. ```go title="Signature" -func (c fiber.Ctx) SaveFileToStorage(fileheader *multipart.FileHeader, path string, storage Storage) error +func (c fiber.Ctx) Links(link ...string) ``` ```go title="Example" -storage := memory.New() - -app.Post("/", func(c fiber.Ctx) error { - // Parse the multipart form: - if form, err := c.MultipartForm(); err == nil { - // => *multipart.Form - - // Get all files from "documents" key: - files := form.File["documents"] - // => []*multipart.FileHeader - - // Loop through files: - for _, file := range files { - fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0]) - // => "tutorial.pdf" 360641 "application/pdf" +app.Get("/", func(c fiber.Ctx) error { + c.Links( + "http://api.example.com/users?page=2", "next", + "http://api.example.com/users?page=5", "last", + ) + // Link: ; rel="next", + // ; rel="last" - // Save the files to storage: - if err := c.SaveFileToStorage(file, fmt.Sprintf("./%s", file.Filename), storage); err != nil { - return err - } - } - return err - } + // ... }) ``` -## Schema - -Contains the request protocol string: `http` or `https` for TLS requests. +### Location -:::info -Please use [`Config.TrustProxy`](fiber.md#trustproxy) to prevent header spoofing if your app is behind a proxy. -::: +Sets the response [Location](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location) HTTP header to the specified path parameter. ```go title="Signature" -func (c fiber.Ctx) Schema() string +func (c fiber.Ctx) Location(path string) ``` ```go title="Example" -// GET http://example.com +app.Post("/", func(c fiber.Ctx) error { + c.Location("http://example.com") -app.Get("/", func(c fiber.Ctx) error { - c.Schema() // "http" + c.Location("/foo/bar") - // ... + return nil }) ``` -## Secure +### Render -A boolean property that is `true` if a **TLS** connection is established. +Renders a view with data and sends a `text/html` response. By default, `Render` uses the default [**Go Template engine**](https://pkg.go.dev/html/template/). If you want to use another view engine, please take a look at our [**Template middleware**](https://docs.gofiber.io/template). ```go title="Signature" -func (c fiber.Ctx) Secure() bool -``` - -```go title="Example" -// Secure() method is equivalent to: -c.Protocol() == "https" +func (c fiber.Ctx) Render(name string, bind any, layouts ...string) error ``` -## Send +### Send Sets the HTTP response body. @@ -1802,7 +1921,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## SendFile +### SendFile Transfers the file from the given path. Sets the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) response HTTP header field based on the **file** extension or format. @@ -1916,7 +2035,7 @@ app.Get("/file", func(c fiber.Ctx) error { For sending multiple files from an embedded file system, [this functionality](../middleware/static.md#serving-files-using-embedfs) can be used. ::: -## SendStatus +### SendStatus Sets the status code and the correct status message in the body if the response body is **empty**. @@ -1939,7 +2058,7 @@ app.Get("/not-found", func(c fiber.Ctx) error { }) ``` -## SendStream +### SendStream Sets the response body to a stream of data and adds an optional body size. @@ -1954,7 +2073,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## SendString +### SendString Sets the response body to a string. @@ -1969,7 +2088,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## SendStreamWriter +### SendStreamWriter Sets the response body stream writer. @@ -2029,7 +2148,7 @@ app.Get("/wait", func(c fiber.Ctx) error { }) ``` -## Set +### Set Sets the response’s HTTP header field to the specified `key`, `value`. @@ -2046,33 +2165,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## SetContext - -Sets the user-specified implementation for the `context.Context` interface. - -```go title="Signature" -func (c fiber.Ctx) SetContext(ctx context.Context) -``` - -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - ctx := context.Background() - c.SetContext(ctx) - // Here ctx could be any context implementation - - // ... -}) -``` - -## Stale - -[https://expressjs.com/en/4x/api.html#req.stale](https://expressjs.com/en/4x/api.html#req.stale) - -```go title="Signature" -func (c fiber.Ctx) Stale() bool -``` - -## Status +### Status Sets the HTTP status for the response. @@ -2099,44 +2192,7 @@ app.Get("/world", func(c fiber.Ctx) error { }) ``` -## String - -Returns a unique string representation of the context. - -```go title="Signature" -func (c fiber.Ctx) String() string -``` - -```go title="Example" -app.Get("/", func(c fiber.Ctx) error { - c.String() // => "#0000000100000001 - 127.0.0.1:3000 <-> 127.0.0.1:61516 - GET http://localhost:3000/" - - // ... -}) -``` - -## Subdomains - -Returns a slice of subdomains in the domain name of the request. - -The application property `subdomain offset`, which defaults to `2`, is used for determining the beginning of the subdomain segments. - -```go title="Signature" -func (c fiber.Ctx) Subdomains(offset ...int) []string -``` - -```go title="Example" -// Host: "tobi.ferrets.example.com" - -app.Get("/", func(c fiber.Ctx) error { - c.Subdomains() // ["ferrets", "tobi"] - c.Subdomains(1) // ["tobi"] - - // ... -}) -``` - -## Type +### Type Sets the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) HTTP header to the MIME type listed [here](https://github.com/nginx/nginx/blob/master/conf/mime.types) specified by the file **extension**. @@ -2160,7 +2216,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## Vary +### Vary Adds the given header field to the [Vary](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary) response header. This will append the header if not already listed; otherwise, it leaves it listed in the current location. @@ -2187,29 +2243,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## ViewBind - -Adds variables to the default view variable map binding to the template engine. -Variables are read by the `Render` method and may be overwritten. - -```go title="Signature" -func (c fiber.Ctx) ViewBind(vars Map) error -``` - -```go title="Example" -app.Use(func(c fiber.Ctx) error { - c.ViewBind(fiber.Map{ - "Title": "Hello, World!", - }) - return c.Next() -}) - -app.Get("/", func(c fiber.Ctx) error { - return c.Render("xxx.tmpl", fiber.Map{}) // Render will use the Title variable -}) -``` - -## Write +### Write Adopts the `Writer` interface. @@ -2225,7 +2259,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## Writef +### Writef Writes a formatted string using a format specifier. @@ -2242,7 +2276,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## WriteString +### WriteString Writes a string to the response body. @@ -2257,25 +2291,7 @@ app.Get("/", func(c fiber.Ctx) error { }) ``` -## XHR - -A boolean property that is `true` if the request’s [X-Requested-With](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) header field is [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest), indicating that the request was issued by a client library (such as [jQuery](https://api.jquery.com/jQuery.ajax/)). - -```go title="Signature" -func (c fiber.Ctx) XHR() bool -``` - -```go title="Example" -// X-Requested-With: XMLHttpRequest - -app.Get("/", func(c fiber.Ctx) error { - c.XHR() // true - - // ... -}) -``` - -## XML +### XML Converts any **interface** or **string** to XML using the standard `encoding/xml` package. diff --git a/req.go b/req.go new file mode 100644 index 00000000000..1b6952ff55c --- /dev/null +++ b/req.go @@ -0,0 +1,159 @@ +package fiber + +import ( + "crypto/tls" + "mime/multipart" +) + +//go:generate ifacemaker --file req.go --struct DefaultReq --iface Req --pkg fiber --output req_interface_gen.go --not-exported true --iface-comment "Req" +type DefaultReq struct { + ctx *DefaultCtx +} + +func (r *DefaultReq) Accepts(offers ...string) string { + return r.ctx.Accepts(offers...) +} + +func (r *DefaultReq) AcceptsCharsets(offers ...string) string { + return r.ctx.AcceptsCharsets(offers...) +} + +func (r *DefaultReq) AcceptsEncodings(offers ...string) string { + return r.ctx.AcceptsEncodings(offers...) +} + +func (r *DefaultReq) AcceptsLanguages(offers ...string) string { + return r.ctx.AcceptsLanguages(offers...) +} + +func (r *DefaultReq) BaseURL() string { + return r.ctx.BaseURL() +} + +func (r *DefaultReq) Body() []byte { + return r.ctx.Body() +} + +func (r *DefaultReq) BodyRaw() []byte { + return r.ctx.BodyRaw() +} + +func (r *DefaultReq) ClientHelloInfo() *tls.ClientHelloInfo { + return r.ctx.ClientHelloInfo() +} + +func (r *DefaultReq) Cookies(key string, defaultValue ...string) string { + return r.ctx.Cookies(key, defaultValue...) +} + +func (r *DefaultReq) FormFile(key string) (*multipart.FileHeader, error) { + return r.ctx.FormFile(key) +} + +func (r *DefaultReq) FormValue(key string, defaultValue ...string) string { + return r.ctx.FormValue(key, defaultValue...) +} + +func (r *DefaultReq) Fresh() bool { + return r.ctx.Fresh() +} + +func (r *DefaultReq) Get(key string, defaultValue ...string) string { + return r.ctx.Get(key, defaultValue...) +} + +func (r *DefaultReq) Host() string { + return r.ctx.Host() +} + +func (r *DefaultReq) Hostname() string { + return r.ctx.Hostname() +} + +func (r *DefaultReq) IP() string { + return r.ctx.IP() +} + +func (r *DefaultReq) IPs() []string { + return r.ctx.IPs() +} + +func (r *DefaultReq) Is(extension string) bool { + return r.ctx.Is(extension) +} + +func (r *DefaultReq) IsFromLocal() bool { + return r.ctx.IsFromLocal() +} + +func (r *DefaultReq) IsProxyTrusted() bool { + return r.ctx.IsProxyTrusted() +} + +func (r *DefaultReq) Method(override ...string) string { + return r.ctx.Method(override...) +} + +func (r *DefaultReq) MultipartForm() (*multipart.Form, error) { + return r.ctx.MultipartForm() +} + +func (r *DefaultReq) OriginalURL() string { + return r.ctx.OriginalURL() +} + +func (r *DefaultReq) Params(key string, defaultValue ...string) string { + return r.ctx.Params(key, defaultValue...) +} + +func (r *DefaultReq) Path(override ...string) string { + return r.ctx.Path(override...) +} + +func (r *DefaultReq) Port() string { + return r.ctx.Port() +} + +func (r *DefaultReq) Protocol() string { + return r.ctx.Protocol() +} + +func (r *DefaultReq) Queries() map[string]string { + return r.ctx.Queries() +} + +func (r *DefaultReq) Query(key string, defaultValue ...string) string { + return r.ctx.Query(key, defaultValue...) +} + +func (r *DefaultReq) Range(size int) (Range, error) { + return r.ctx.Range(size) +} + +func (r *DefaultReq) Route() *Route { + return r.ctx.Route() +} + +func (r *DefaultReq) SaveFile(fileheader *multipart.FileHeader, path string) error { + return r.ctx.SaveFile(fileheader, path) +} + +func (r *DefaultReq) SaveFileToStorage(fileheader *multipart.FileHeader, path string, storage Storage) error { + return r.ctx.SaveFileToStorage(fileheader, path, storage) +} + +func (r *DefaultReq) Secure() bool { + return r.ctx.Secure() +} + +func (r *DefaultReq) Stale() bool { + return r.ctx.Stale() +} + +func (r *DefaultReq) Subdomains(offset ...int) []string { + return r.ctx.Subdomains(offset...) +} + +func (r *DefaultReq) XHR() bool { + return r.ctx.XHR() +} diff --git a/req_interface_gen.go b/req_interface_gen.go new file mode 100644 index 00000000000..643854b7012 --- /dev/null +++ b/req_interface_gen.go @@ -0,0 +1,49 @@ +// Code generated by ifacemaker; DO NOT EDIT. + +package fiber + +import ( + "crypto/tls" + "mime/multipart" +) + +// Req +type Req interface { + Accepts(offers ...string) string + AcceptsCharsets(offers ...string) string + AcceptsEncodings(offers ...string) string + AcceptsLanguages(offers ...string) string + BaseURL() string + Body() []byte + BodyRaw() []byte + ClientHelloInfo() *tls.ClientHelloInfo + Cookies(key string, defaultValue ...string) string + FormFile(key string) (*multipart.FileHeader, error) + FormValue(key string, defaultValue ...string) string + Fresh() bool + Get(key string, defaultValue ...string) string + Host() string + Hostname() string + IP() string + IPs() []string + Is(extension string) bool + IsFromLocal() bool + IsProxyTrusted() bool + Method(override ...string) string + MultipartForm() (*multipart.Form, error) + OriginalURL() string + Params(key string, defaultValue ...string) string + Path(override ...string) string + Port() string + Protocol() string + Queries() map[string]string + Query(key string, defaultValue ...string) string + Range(size int) (Range, error) + Route() *Route + SaveFile(fileheader *multipart.FileHeader, path string) error + SaveFileToStorage(fileheader *multipart.FileHeader, path string, storage Storage) error + Secure() bool + Stale() bool + Subdomains(offset ...int) []string + XHR() bool +} diff --git a/res.go b/res.go new file mode 100644 index 00000000000..c2dd6f7f558 --- /dev/null +++ b/res.go @@ -0,0 +1,118 @@ +package fiber + +import ( + "bufio" +) + +//go:generate ifacemaker --file res.go --struct DefaultRes --iface Res --pkg fiber --output res_interface_gen.go --not-exported true --iface-comment "Res" +type DefaultRes struct { + ctx *DefaultCtx +} + +func (r *DefaultRes) Append(field string, values ...string) { + r.ctx.Append(field, values...) +} + +func (r *DefaultRes) Attachment(filename ...string) { + r.ctx.Attachment(filename...) +} + +func (r *DefaultRes) AutoFormat(body any) error { + return r.ctx.AutoFormat(body) +} + +func (r *DefaultRes) CBOR(body any, ctype ...string) error { + return r.ctx.CBOR(body, ctype...) +} + +func (r *DefaultRes) ClearCookie(key ...string) { + r.ctx.ClearCookie(key...) +} + +func (r *DefaultRes) Cookie(cookie *Cookie) { + r.ctx.Cookie(cookie) +} + +func (r *DefaultRes) Download(file string, filename ...string) error { + return r.ctx.Download(file, filename...) +} + +func (r *DefaultRes) Format(handlers ...ResFmt) error { + return r.ctx.Format(handlers...) +} + +func (r *DefaultRes) Get(key string, defaultValue ...string) string { + return r.ctx.GetRespHeader(key, defaultValue...) +} + +func (r *DefaultRes) JSON(body any, ctype ...string) error { + return r.ctx.JSON(body, ctype...) +} + +func (r *DefaultRes) JSONP(data any, callback ...string) error { + return r.ctx.JSONP(data, callback...) +} + +func (r *DefaultRes) Links(link ...string) { + r.ctx.Links(link...) +} + +func (r *DefaultRes) Location(path string) { + r.ctx.Location(path) +} + +func (r *DefaultRes) Render(name string, bind any, layouts ...string) error { + return r.ctx.Render(name, bind, layouts...) +} + +func (r *DefaultRes) Send(body []byte) error { + return r.ctx.Send(body) +} + +func (r *DefaultRes) SendFile(file string, config ...SendFile) error { + return r.ctx.SendFile(file, config...) +} + +func (r *DefaultRes) SendStatus(status int) error { + return r.ctx.SendStatus(status) +} + +func (r *DefaultRes) SendString(body string) error { + return r.ctx.SendString(body) +} + +func (r *DefaultRes) SendStreamWriter(streamWriter func(*bufio.Writer)) error { + return r.ctx.SendStreamWriter(streamWriter) +} + +func (r *DefaultRes) Set(key, val string) { + r.ctx.Set(key, val) +} + +func (r *DefaultRes) Status(status int) Ctx { + return r.ctx.Status(status) +} + +func (r *DefaultRes) Type(extension string, charset ...string) Ctx { + return r.ctx.Type(extension, charset...) +} + +func (r *DefaultRes) Vary(fields ...string) { + r.ctx.Vary(fields...) +} + +func (r *DefaultRes) Write(p []byte) (int, error) { + return r.ctx.Write(p) +} + +func (r *DefaultRes) Writef(f string, a ...any) (int, error) { + return r.ctx.Writef(f, a...) +} + +func (r *DefaultRes) WriteString(s string) (int, error) { + return r.ctx.WriteString(s) +} + +func (r *DefaultRes) XML(data any) error { + return r.ctx.XML(data) +} diff --git a/res_interface_gen.go b/res_interface_gen.go new file mode 100644 index 00000000000..93a4036a65a --- /dev/null +++ b/res_interface_gen.go @@ -0,0 +1,38 @@ +// Code generated by ifacemaker; DO NOT EDIT. + +package fiber + +import ( + "bufio" +) + +// Res +type Res interface { + Append(field string, values ...string) + Attachment(filename ...string) + AutoFormat(body any) error + CBOR(body any, ctype ...string) error + ClearCookie(key ...string) + Cookie(cookie *Cookie) + Download(file string, filename ...string) error + Format(handlers ...ResFmt) error + Get(key string, defaultValue ...string) string + JSON(body any, ctype ...string) error + JSONP(data any, callback ...string) error + Links(link ...string) + Location(path string) + Render(name string, bind any, layouts ...string) error + Send(body []byte) error + SendFile(file string, config ...SendFile) error + SendStatus(status int) error + SendString(body string) error + SendStreamWriter(streamWriter func(*bufio.Writer)) error + Set(key, val string) + Status(status int) Ctx + Type(extension string, charset ...string) Ctx + Vary(fields ...string) + Write(p []byte) (int, error) + Writef(f string, a ...any) (int, error) + WriteString(s string) (int, error) + XML(data any) error +}