[v3 Maintenance]: Consolidate and Document Core Changes in v3 (#2934)

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3

* [v3 Maintenance]: Consolidate and Document Core Changes in v3
pull/2983/head
RW 2024-04-23 08:18:19 +02:00 committed by GitHub
parent 4d1e993cdb
commit 077968abec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 2320 additions and 1438 deletions

16
app.go
View File

@ -276,6 +276,8 @@ type Config struct {
// StreamRequestBody enables request body streaming,
// and calls the handler sooner when given body is
// larger than the current limit.
//
// Default: false
StreamRequestBody bool
// Will not pre parse Multipart Form data if set to true.
@ -284,6 +286,8 @@ type Config struct {
// multipart form data as a binary blob, or choose when to parse the data.
//
// Server pre parses multipart form data by default.
//
// Default: false
DisablePreParseMultipartForm bool
// Aggressively reduces memory usage at the cost of higher CPU usage
@ -296,14 +300,6 @@ type Config struct {
// Default: false
ReduceMemoryUsage bool `json:"reduce_memory_usage"`
// FEATURE: v2.3.x
// The router executes the same handler by default if StrictRouting or CaseSensitive is disabled.
// Enabling RedirectFixedPath will change this behavior into a client redirect to the original route path.
// Using the status code 301 for GET requests and 308 for all other request methods.
//
// Default: false
// RedirectFixedPath bool
// When set by an external client of Fiber it will use the provided implementation of a
// JSONMarshal
//
@ -595,13 +591,13 @@ func (app *App) RegisterCustomConstraint(constraint CustomConstraint) {
app.customConstraints = append(app.customConstraints, constraint)
}
// You can register custom binders to use as Bind().Custom("name").
// RegisterCustomBinder Allows to register custom binders to use as Bind().Custom("name").
// They should be compatible with CustomBinder interface.
func (app *App) RegisterCustomBinder(binder CustomBinder) {
app.customBinders = append(app.customBinders, binder)
}
// You can use SetTLSHandler to use ClientHelloInfo when using TLS with Listener.
// SetTLSHandler Can be used to set ClientHelloInfo when using TLS with Listener.
func (app *App) SetTLSHandler(tlsHandler *TLSHandler) {
// Attach the tlsHandler to the config
app.mutex.Lock()

43
bind.go
View File

@ -5,26 +5,25 @@ import (
"github.com/gofiber/utils/v2"
)
// An interface to register custom binders.
// CustomBinder An interface to register custom binders.
type CustomBinder interface {
Name() string
MIMETypes() []string
Parse(c Ctx, out any) error
}
// An interface to register custom struct validator for binding.
// StructValidator is an interface to register custom struct validator for binding.
type StructValidator interface {
Engine() any
ValidateStruct(out any) error
Validate(out any) error
}
// Bind struct
type Bind struct {
ctx *DefaultCtx
ctx Ctx
should bool
}
// To handle binder errors manually, you can prefer Should method.
// Should To handle binder errors manually, you can prefer Should method.
// It's default behavior of binder.
func (b *Bind) Should() *Bind {
b.should = true
@ -32,7 +31,7 @@ func (b *Bind) Should() *Bind {
return b
}
// If you want to handle binder errors automatically, you can use Must.
// Must If you want to handle binder errors automatically, you can use Must.
// If there's an error it'll return error and 400 as HTTP status.
func (b *Bind) Must() *Bind {
b.should = false
@ -52,15 +51,15 @@ func (b *Bind) returnErr(err error) error {
// Struct validation.
func (b *Bind) validateStruct(out any) error {
validator := b.ctx.app.config.StructValidator
validator := b.ctx.App().config.StructValidator
if validator != nil {
return validator.ValidateStruct(out)
return validator.Validate(out)
}
return nil
}
// To use custom binders, you have to use this method.
// Custom To use custom binders, you have to use this method.
// You can register them from RegisterCustomBinder method of Fiber instance.
// They're checked by name, if it's not found, it will return an error.
// NOTE: Should/Must is still valid for Custom binders.
@ -103,7 +102,7 @@ func (b *Bind) Cookie(out any) error {
return b.validateStruct(out)
}
// QueryParser binds the query string into the struct, map[string]string and map[string][]string.
// Query binds the query string into the struct, map[string]string and map[string][]string.
func (b *Bind) Query(out any) error {
if err := b.returnErr(binder.QueryBinder.Bind(b.ctx.Context(), out)); err != nil {
return err
@ -141,7 +140,7 @@ func (b *Bind) Form(out any) error {
// URI binds the route parameters into the struct, map[string]string and map[string][]string.
func (b *Bind) URI(out any) error {
if err := b.returnErr(binder.URIBinder.Bind(b.ctx.route.Params, b.ctx.Params, out)); err != nil {
if err := b.returnErr(binder.URIBinder.Bind(b.ctx.Route().Params, b.ctx.Params, out)); err != nil {
return err
}
@ -167,6 +166,16 @@ func (b *Bind) Body(out any) error {
ctype := utils.ToLower(utils.UnsafeString(b.ctx.Context().Request.Header.ContentType()))
ctype = binder.FilterFlags(utils.ParseVendorSpecificContentType(ctype))
// Check custom binders
binders := b.ctx.App().customBinders
for _, customBinder := range binders {
for _, mime := range customBinder.MIMETypes() {
if mime == ctype {
return b.returnErr(customBinder.Parse(b.ctx, out))
}
}
}
// Parse body accordingly
switch ctype {
case MIMEApplicationJSON:
@ -179,16 +188,6 @@ func (b *Bind) Body(out any) error {
return b.MultipartForm(out)
}
// Check custom binders
binders := b.ctx.App().customBinders
for _, customBinder := range binders {
for _, mime := range customBinder.MIMETypes() {
if mime == ctype {
return b.returnErr(customBinder.Parse(b.ctx, out))
}
}
}
// No suitable content type found
return ErrUnprocessableEntity
}

View File

@ -1547,11 +1547,7 @@ func Test_Bind_Must(t *testing.T) {
// simple struct validator for testing
type structValidator struct{}
func (*structValidator) Engine() any {
return ""
}
func (*structValidator) ValidateStruct(out any) error {
func (*structValidator) Validate(out any) error {
out = reflect.ValueOf(out).Elem().Interface()
sq, ok := out.(simpleQuery)
if !ok {

331
constants.go Normal file
View File

@ -0,0 +1,331 @@
package fiber
// HTTP methods were copied from net/http.
const (
MethodGet = "GET" // RFC 7231, 4.3.1
MethodHead = "HEAD" // RFC 7231, 4.3.2
MethodPost = "POST" // RFC 7231, 4.3.3
MethodPut = "PUT" // RFC 7231, 4.3.4
MethodPatch = "PATCH" // RFC 5789
MethodDelete = "DELETE" // RFC 7231, 4.3.5
MethodConnect = "CONNECT" // RFC 7231, 4.3.6
MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
MethodTrace = "TRACE" // RFC 7231, 4.3.8
methodUse = "USE"
)
// MIME types that are commonly used
const (
MIMETextXML = "text/xml"
MIMETextHTML = "text/html"
MIMETextPlain = "text/plain"
MIMETextJavaScript = "text/javascript"
MIMEApplicationXML = "application/xml"
MIMEApplicationJSON = "application/json"
// Deprecated: use MIMETextJavaScript instead
MIMEApplicationJavaScript = "application/javascript"
MIMEApplicationForm = "application/x-www-form-urlencoded"
MIMEOctetStream = "application/octet-stream"
MIMEMultipartForm = "multipart/form-data"
MIMETextXMLCharsetUTF8 = "text/xml; charset=utf-8"
MIMETextHTMLCharsetUTF8 = "text/html; charset=utf-8"
MIMETextPlainCharsetUTF8 = "text/plain; charset=utf-8"
MIMETextJavaScriptCharsetUTF8 = "text/javascript; charset=utf-8"
MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=utf-8"
MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
// Deprecated: use MIMETextJavaScriptCharsetUTF8 instead
MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8"
)
// HTTP status codes were copied from net/http with the following updates:
// - Rename StatusNonAuthoritativeInfo to StatusNonAuthoritativeInformation
// - Add StatusSwitchProxy (306)
// NOTE: Keep this list in sync with statusMessage
const (
StatusContinue = 100 // RFC 9110, 15.2.1
StatusSwitchingProtocols = 101 // RFC 9110, 15.2.2
StatusProcessing = 102 // RFC 2518, 10.1
StatusEarlyHints = 103 // RFC 8297
StatusOK = 200 // RFC 9110, 15.3.1
StatusCreated = 201 // RFC 9110, 15.3.2
StatusAccepted = 202 // RFC 9110, 15.3.3
StatusNonAuthoritativeInformation = 203 // RFC 9110, 15.3.4
StatusNoContent = 204 // RFC 9110, 15.3.5
StatusResetContent = 205 // RFC 9110, 15.3.6
StatusPartialContent = 206 // RFC 9110, 15.3.7
StatusMultiStatus = 207 // RFC 4918, 11.1
StatusAlreadyReported = 208 // RFC 5842, 7.1
StatusIMUsed = 226 // RFC 3229, 10.4.1
StatusMultipleChoices = 300 // RFC 9110, 15.4.1
StatusMovedPermanently = 301 // RFC 9110, 15.4.2
StatusFound = 302 // RFC 9110, 15.4.3
StatusSeeOther = 303 // RFC 9110, 15.4.4
StatusNotModified = 304 // RFC 9110, 15.4.5
StatusUseProxy = 305 // RFC 9110, 15.4.6
StatusSwitchProxy = 306 // RFC 9110, 15.4.7 (Unused)
StatusTemporaryRedirect = 307 // RFC 9110, 15.4.8
StatusPermanentRedirect = 308 // RFC 9110, 15.4.9
StatusBadRequest = 400 // RFC 9110, 15.5.1
StatusUnauthorized = 401 // RFC 9110, 15.5.2
StatusPaymentRequired = 402 // RFC 9110, 15.5.3
StatusForbidden = 403 // RFC 9110, 15.5.4
StatusNotFound = 404 // RFC 9110, 15.5.5
StatusMethodNotAllowed = 405 // RFC 9110, 15.5.6
StatusNotAcceptable = 406 // RFC 9110, 15.5.7
StatusProxyAuthRequired = 407 // RFC 9110, 15.5.8
StatusRequestTimeout = 408 // RFC 9110, 15.5.9
StatusConflict = 409 // RFC 9110, 15.5.10
StatusGone = 410 // RFC 9110, 15.5.11
StatusLengthRequired = 411 // RFC 9110, 15.5.12
StatusPreconditionFailed = 412 // RFC 9110, 15.5.13
StatusRequestEntityTooLarge = 413 // RFC 9110, 15.5.14
StatusRequestURITooLong = 414 // RFC 9110, 15.5.15
StatusUnsupportedMediaType = 415 // RFC 9110, 15.5.16
StatusRequestedRangeNotSatisfiable = 416 // RFC 9110, 15.5.17
StatusExpectationFailed = 417 // RFC 9110, 15.5.18
StatusTeapot = 418 // RFC 9110, 15.5.19 (Unused)
StatusMisdirectedRequest = 421 // RFC 9110, 15.5.20
StatusUnprocessableEntity = 422 // RFC 9110, 15.5.21
StatusLocked = 423 // RFC 4918, 11.3
StatusFailedDependency = 424 // RFC 4918, 11.4
StatusTooEarly = 425 // RFC 8470, 5.2.
StatusUpgradeRequired = 426 // RFC 9110, 15.5.22
StatusPreconditionRequired = 428 // RFC 6585, 3
StatusTooManyRequests = 429 // RFC 6585, 4
StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5
StatusUnavailableForLegalReasons = 451 // RFC 7725, 3
StatusInternalServerError = 500 // RFC 9110, 15.6.1
StatusNotImplemented = 501 // RFC 9110, 15.6.2
StatusBadGateway = 502 // RFC 9110, 15.6.3
StatusServiceUnavailable = 503 // RFC 9110, 15.6.4
StatusGatewayTimeout = 504 // RFC 9110, 15.6.5
StatusHTTPVersionNotSupported = 505 // RFC 9110, 15.6.6
StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1
StatusInsufficientStorage = 507 // RFC 4918, 11.5
StatusLoopDetected = 508 // RFC 5842, 7.2
StatusNotExtended = 510 // RFC 2774, 7
StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)
// Errors
var (
ErrBadRequest = NewError(StatusBadRequest) // 400
ErrUnauthorized = NewError(StatusUnauthorized) // 401
ErrPaymentRequired = NewError(StatusPaymentRequired) // 402
ErrForbidden = NewError(StatusForbidden) // 403
ErrNotFound = NewError(StatusNotFound) // 404
ErrMethodNotAllowed = NewError(StatusMethodNotAllowed) // 405
ErrNotAcceptable = NewError(StatusNotAcceptable) // 406
ErrProxyAuthRequired = NewError(StatusProxyAuthRequired) // 407
ErrRequestTimeout = NewError(StatusRequestTimeout) // 408
ErrConflict = NewError(StatusConflict) // 409
ErrGone = NewError(StatusGone) // 410
ErrLengthRequired = NewError(StatusLengthRequired) // 411
ErrPreconditionFailed = NewError(StatusPreconditionFailed) // 412
ErrRequestEntityTooLarge = NewError(StatusRequestEntityTooLarge) // 413
ErrRequestURITooLong = NewError(StatusRequestURITooLong) // 414
ErrUnsupportedMediaType = NewError(StatusUnsupportedMediaType) // 415
ErrRequestedRangeNotSatisfiable = NewError(StatusRequestedRangeNotSatisfiable) // 416
ErrExpectationFailed = NewError(StatusExpectationFailed) // 417
ErrTeapot = NewError(StatusTeapot) // 418
ErrMisdirectedRequest = NewError(StatusMisdirectedRequest) // 421
ErrUnprocessableEntity = NewError(StatusUnprocessableEntity) // 422
ErrLocked = NewError(StatusLocked) // 423
ErrFailedDependency = NewError(StatusFailedDependency) // 424
ErrTooEarly = NewError(StatusTooEarly) // 425
ErrUpgradeRequired = NewError(StatusUpgradeRequired) // 426
ErrPreconditionRequired = NewError(StatusPreconditionRequired) // 428
ErrTooManyRequests = NewError(StatusTooManyRequests) // 429
ErrRequestHeaderFieldsTooLarge = NewError(StatusRequestHeaderFieldsTooLarge) // 431
ErrUnavailableForLegalReasons = NewError(StatusUnavailableForLegalReasons) // 451
ErrInternalServerError = NewError(StatusInternalServerError) // 500
ErrNotImplemented = NewError(StatusNotImplemented) // 501
ErrBadGateway = NewError(StatusBadGateway) // 502
ErrServiceUnavailable = NewError(StatusServiceUnavailable) // 503
ErrGatewayTimeout = NewError(StatusGatewayTimeout) // 504
ErrHTTPVersionNotSupported = NewError(StatusHTTPVersionNotSupported) // 505
ErrVariantAlsoNegotiates = NewError(StatusVariantAlsoNegotiates) // 506
ErrInsufficientStorage = NewError(StatusInsufficientStorage) // 507
ErrLoopDetected = NewError(StatusLoopDetected) // 508
ErrNotExtended = NewError(StatusNotExtended) // 510
ErrNetworkAuthenticationRequired = NewError(StatusNetworkAuthenticationRequired) // 511
)
// HTTP Headers were copied from net/http.
const (
HeaderAuthorization = "Authorization"
HeaderProxyAuthenticate = "Proxy-Authenticate"
HeaderProxyAuthorization = "Proxy-Authorization"
HeaderWWWAuthenticate = "WWW-Authenticate"
HeaderAge = "Age"
HeaderCacheControl = "Cache-Control"
HeaderClearSiteData = "Clear-Site-Data"
HeaderExpires = "Expires"
HeaderPragma = "Pragma"
HeaderWarning = "Warning"
HeaderAcceptCH = "Accept-CH"
HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
HeaderContentDPR = "Content-DPR"
HeaderDPR = "DPR"
HeaderEarlyData = "Early-Data"
HeaderSaveData = "Save-Data"
HeaderViewportWidth = "Viewport-Width"
HeaderWidth = "Width"
HeaderETag = "ETag"
HeaderIfMatch = "If-Match"
HeaderIfModifiedSince = "If-Modified-Since"
HeaderIfNoneMatch = "If-None-Match"
HeaderIfUnmodifiedSince = "If-Unmodified-Since"
HeaderLastModified = "Last-Modified"
HeaderVary = "Vary"
HeaderConnection = "Connection"
HeaderKeepAlive = "Keep-Alive"
HeaderAccept = "Accept"
HeaderAcceptCharset = "Accept-Charset"
HeaderAcceptEncoding = "Accept-Encoding"
HeaderAcceptLanguage = "Accept-Language"
HeaderCookie = "Cookie"
HeaderExpect = "Expect"
HeaderMaxForwards = "Max-Forwards"
HeaderSetCookie = "Set-Cookie"
HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
HeaderAccessControlMaxAge = "Access-Control-Max-Age"
HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
HeaderOrigin = "Origin"
HeaderTimingAllowOrigin = "Timing-Allow-Origin"
HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
HeaderDNT = "DNT"
HeaderTk = "Tk"
HeaderContentDisposition = "Content-Disposition"
HeaderContentEncoding = "Content-Encoding"
HeaderContentLanguage = "Content-Language"
HeaderContentLength = "Content-Length"
HeaderContentLocation = "Content-Location"
HeaderContentType = "Content-Type"
HeaderForwarded = "Forwarded"
HeaderVia = "Via"
HeaderXForwardedFor = "X-Forwarded-For"
HeaderXForwardedHost = "X-Forwarded-Host"
HeaderXForwardedProto = "X-Forwarded-Proto"
HeaderXForwardedProtocol = "X-Forwarded-Protocol"
HeaderXForwardedSsl = "X-Forwarded-Ssl"
HeaderXUrlScheme = "X-Url-Scheme"
HeaderLocation = "Location"
HeaderFrom = "From"
HeaderHost = "Host"
HeaderReferer = "Referer"
HeaderReferrerPolicy = "Referrer-Policy"
HeaderUserAgent = "User-Agent"
HeaderAllow = "Allow"
HeaderServer = "Server"
HeaderAcceptRanges = "Accept-Ranges"
HeaderContentRange = "Content-Range"
HeaderIfRange = "If-Range"
HeaderRange = "Range"
HeaderContentSecurityPolicy = "Content-Security-Policy"
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy"
HeaderExpectCT = "Expect-CT"
HeaderPermissionsPolicy = "Permissions-Policy"
HeaderPublicKeyPins = "Public-Key-Pins"
HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only"
HeaderStrictTransportSecurity = "Strict-Transport-Security"
HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests"
HeaderXContentTypeOptions = "X-Content-Type-Options"
HeaderXDownloadOptions = "X-Download-Options"
HeaderXFrameOptions = "X-Frame-Options"
HeaderXPoweredBy = "X-Powered-By"
HeaderXXSSProtection = "X-XSS-Protection"
HeaderLastEventID = "Last-Event-ID"
HeaderNEL = "NEL"
HeaderPingFrom = "Ping-From"
HeaderPingTo = "Ping-To"
HeaderReportTo = "Report-To"
HeaderTE = "TE"
HeaderTrailer = "Trailer"
HeaderTransferEncoding = "Transfer-Encoding"
HeaderSecWebSocketAccept = "Sec-WebSocket-Accept"
HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions"
HeaderSecWebSocketKey = "Sec-WebSocket-Key"
HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol"
HeaderSecWebSocketVersion = "Sec-WebSocket-Version"
HeaderAcceptPatch = "Accept-Patch"
HeaderAcceptPushPolicy = "Accept-Push-Policy"
HeaderAcceptSignature = "Accept-Signature"
HeaderAltSvc = "Alt-Svc"
HeaderDate = "Date"
HeaderIndex = "Index"
HeaderLargeAllocation = "Large-Allocation"
HeaderLink = "Link"
HeaderPushPolicy = "Push-Policy"
HeaderRetryAfter = "Retry-After"
HeaderServerTiming = "Server-Timing"
HeaderSignature = "Signature"
HeaderSignedHeaders = "Signed-Headers"
HeaderSourceMap = "SourceMap"
HeaderUpgrade = "Upgrade"
HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
HeaderXPingback = "X-Pingback"
HeaderXRequestID = "X-Request-ID"
HeaderXRequestedWith = "X-Requested-With"
HeaderXRobotsTag = "X-Robots-Tag"
HeaderXUACompatible = "X-UA-Compatible"
HeaderAccessControlAllowPrivateNetwork = "Access-Control-Allow-Private-Network"
HeaderAccessControlRequestPrivateNetwork = "Access-Control-Request-Private-Network"
)
// Network types that are commonly used
const (
NetworkTCP = "tcp"
NetworkTCP4 = "tcp4"
NetworkTCP6 = "tcp6"
)
// Compression types
const (
StrGzip = "gzip"
StrBr = "br"
StrDeflate = "deflate"
StrBrotli = "brotli"
)
// Cookie SameSite
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
const (
CookieSameSiteDisabled = "disabled" // not in RFC, just control "SameSite" attribute will not be set.
CookieSameSiteLaxMode = "lax"
CookieSameSiteStrictMode = "strict"
CookieSameSiteNoneMode = "none"
)
// Route Constraints
const (
ConstraintInt = "int"
ConstraintBool = "bool"
ConstraintFloat = "float"
ConstraintAlpha = "alpha"
ConstraintGUID = "guid"
ConstraintMinLen = "minLen"
ConstraintMaxLen = "maxLen"
ConstraintLen = "len"
ConstraintBetweenLen = "betweenLen"
ConstraintMinLenLower = "minlen"
ConstraintMaxLenLower = "maxlen"
ConstraintBetweenLenLower = "betweenlen"
ConstraintMin = "min"
ConstraintMax = "max"
ConstraintRange = "range"
ConstraintDatetime = "datetime"
ConstraintRegex = "regex"
)

12
ctx.go
View File

@ -594,6 +594,9 @@ func (c *DefaultCtx) GetReqHeaders() map[string][]string {
// Host contains the host derived from the X-Forwarded-Host or Host HTTP header.
// Returned value is only valid within the handler. Do not store any references.
// In a network context, `Host` refers to the combination of a hostname and potentially a port number used for connecting,
// while `Hostname` refers specifically to the name assigned to a device on a network, excluding any port information.
// Example: URL: https://example.com:8080 -> Host: example.com:8080
// Make copies or use the Immutable setting instead.
// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy.
func (c *DefaultCtx) Host() string {
@ -611,6 +614,7 @@ func (c *DefaultCtx) Host() string {
// Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the c.Host() method.
// Returned value is only valid within the handler. Do not store any references.
// Example: URL: https://example.com:8080 -> Hostname: example.com
// Make copies or use the Immutable setting instead.
// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy.
func (c *DefaultCtx) Hostname() string {
@ -1202,9 +1206,9 @@ func (c *DefaultCtx) Redirect() *Redirect {
return c.redirect
}
// Bind Add vars to default view var map binding to template engine.
// ViewBind Add vars to default view var map binding to template engine.
// Variables are read by the Render method and may be overwritten.
func (c *DefaultCtx) BindVars(vars Map) error {
func (c *DefaultCtx) ViewBind(vars Map) error {
// init viewBindMap - lazy map
for k, v := range vars {
c.viewBindMap.Store(k, v)
@ -1694,7 +1698,7 @@ func (c *DefaultCtx) IsFromLocal() bool {
return c.isLocalHost(c.fasthttp.RemoteIP().String())
}
// You can bind body, cookie, headers etc. into the map, map slice, struct easily by using Binding method.
// Bind You can bind body, cookie, headers etc. into the map, map slice, struct easily by using Binding method.
// It gives custom binding support, detailed binding options and more.
// Replacement of: BodyParser, ParamsParser, GetReqHeaders, GetRespHeaders, AllParams, QueryParser, ReqHeaderParser
func (c *DefaultCtx) Bind() *Bind {
@ -1707,7 +1711,7 @@ func (c *DefaultCtx) Bind() *Bind {
return c.bind
}
// Converts a string value to a specified type, handling errors and optional default values.
// Convert a string value to a specified type, handling errors and optional default values.
func Convert[T any](value string, convertor func(string) (T, error), defaultValue ...T) (T, error) {
converted, err := convertor(value)
if err != nil {

View File

@ -40,6 +40,13 @@ type Ctx interface {
// Attachment sets the HTTP response Content-Disposition header field to attachment.
Attachment(filename ...string)
// AutoFormat performs content-negotiation on the Accept HTTP header.
// It uses 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.
// If the header is not specified or there is no proper format, text/plain is used.
AutoFormat(body any) error
// BaseURL returns (protocol + host + base path).
BaseURL() string
@ -97,13 +104,6 @@ type Ctx interface {
// StatusNotAcceptable is sent.
Format(handlers ...ResFmt) error
// AutoFormat performs content-negotiation on the Accept HTTP header.
// It uses 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.
// If the header is not specified or there is no proper format, text/plain is used.
AutoFormat(body any) error
// FormFile returns the first file by key from a MultipartForm.
FormFile(key string) (*multipart.FileHeader, error)
@ -146,12 +146,16 @@ type Ctx interface {
// Host contains the host derived from the X-Forwarded-Host or Host HTTP header.
// Returned value is only valid within the handler. Do not store any references.
// In a network context, `Host` refers to the combination of a hostname and potentially a port number used for connecting,
// while `Hostname` refers specifically to the name assigned to a device on a network, excluding any port information.
// Example: URL: https://example.com:8080 -> Host: example.com:8080
// Make copies or use the Immutable setting instead.
// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy.
Host() string
// Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the c.Host() method.
// Returned value is only valid within the handler. Do not store any references.
// Example: URL: https://example.com:8080 -> Hostname: example.com
// Make copies or use the Immutable setting instead.
// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy.
Hostname() string
@ -274,9 +278,9 @@ type Ctx interface {
// You can use Redirect().To(), Redirect().Route() and Redirect().Back() for redirection.
Redirect() *Redirect
// Add vars to default view var map binding to template engine.
// ViewBind Add vars to default view var map binding to template engine.
// Variables are read by the Render method and may be overwritten.
BindVars(vars Map) error
ViewBind(vars Map) error
// GetRouteURL generates URLs to named routes, with parameters. URLs are relative, for example: "/user/1831"
GetRouteURL(routeName string, params Map) (string, error)
@ -367,7 +371,7 @@ type Ctx interface {
// Reset is a method to reset context fields by given request when to use server handlers.
Reset(fctx *fasthttp.RequestCtx)
// You can bind body, cookie, headers etc. into the map, map slice, struct easily by using Binding method.
// Bind You can bind body, cookie, headers etc. into the map, map slice, struct easily by using Binding method.
// It gives custom binding support, detailed binding options and more.
// Replacement of: BodyParser, ParamsParser, GetReqHeaders, GetRespHeaders, AllParams, QueryParser, ReqHeaderParser
Bind() *Bind

View File

@ -1353,8 +1353,8 @@ func Benchmark_Ctx_Fresh_WithNoCache(b *testing.B) {
}
}
// go test -run Test_Ctx_Parsers -v
func Test_Ctx_Parsers(t *testing.T) {
// go test -run Test_Ctx_Binders -v
func Test_Ctx_Binders(t *testing.T) {
t.Parallel()
// setup
app := New()
@ -1386,7 +1386,7 @@ func Test_Ctx_Parsers(t *testing.T) {
require.Equal(t, []string{"foo", "bar", "test"}, testStruct.TestEmbeddedStruct.Names)
}
t.Run("BodyParser:xml", func(t *testing.T) {
t.Run("Body:xml", func(t *testing.T) {
t.Parallel()
withValues(t, func(c Ctx, testStruct *TestStruct) error {
c.Request().Header.SetContentType(MIMEApplicationXML)
@ -1394,7 +1394,7 @@ func Test_Ctx_Parsers(t *testing.T) {
return c.Bind().Body(testStruct)
})
})
t.Run("BodyParser:form", func(t *testing.T) {
t.Run("Body:form", func(t *testing.T) {
t.Parallel()
withValues(t, func(c Ctx, testStruct *TestStruct) error {
c.Request().Header.SetContentType(MIMEApplicationForm)
@ -1410,7 +1410,7 @@ func Test_Ctx_Parsers(t *testing.T) {
return c.Bind().Body(testStruct)
})
})
t.Run("BodyParser:multiform", func(t *testing.T) {
t.Run("Body:multiform", func(t *testing.T) {
t.Parallel()
withValues(t, func(c Ctx, testStruct *TestStruct) error {
body := []byte("--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nfoo\r\n--b\r\nContent-Disposition: form-data; name=\"class\"\r\n\r\n111\r\n--b\r\nContent-Disposition: form-data; name=\"name2\"\r\n\r\nbar\r\n--b\r\nContent-Disposition: form-data; name=\"class2\"\r\n\r\n222\r\n--b\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\nfoo\r\n--b\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\nbar\r\n--b\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\ntest\r\n--b--")
@ -1420,31 +1420,31 @@ func Test_Ctx_Parsers(t *testing.T) {
return c.Bind().Body(testStruct)
})
})
t.Run("CookieParser", func(t *testing.T) {
t.Run("Cookie", func(t *testing.T) {
t.Parallel()
withValues(t, func(c Ctx, testStruct *TestStruct) error {
c.Request().Header.Set("Cookie", "name=foo;name2=bar;class=111;class2=222;names=foo,bar,test")
return c.Bind().Cookie(testStruct)
})
})
t.Run("QueryParser", func(t *testing.T) {
t.Run("Query", func(t *testing.T) {
t.Parallel()
withValues(t, func(c Ctx, testStruct *TestStruct) error {
c.Request().URI().SetQueryString("name=foo&name2=bar&class=111&class2=222&names=foo,bar,test")
return c.Bind().Query(testStruct)
})
})
t.Run("ParamsParser", func(t *testing.T) {
t.Skip("ParamsParser is not ready for v3")
t.Run("URI", func(t *testing.T) {
t.Skip("URI is not ready for v3")
//nolint:gocritic // TODO: uncomment
// t.Parallel()
// withValues(t, func(c Ctx, testStruct *TestStruct) error {
// c.route = &Route{Params: []string{"name", "name2", "class", "class2"}}
// c.values = [30]string{"foo", "bar", "111", "222"}
// return c.ParamsParser(testStruct)
// })
//t.Parallel()
//withValues(t, func(c Ctx, testStruct *TestStruct) error {
// c.Route().Params = []string{"name", "name2", "class", "class2"}
// c.Params().value = [30]string{"foo", "bar", "111", "222"}
// return c.Bind().URI(testStruct)
//})
})
t.Run("ReqHeaderParser", func(t *testing.T) {
t.Run("ReqHeader", func(t *testing.T) {
t.Parallel()
withValues(t, func(c Ctx, testStruct *TestStruct) error {
c.Request().Header.Add("name", "foo")
@ -3441,13 +3441,13 @@ func Test_Ctx_RenderWithLocals(t *testing.T) {
})
}
func Test_Ctx_RenderWithBindVars(t *testing.T) {
func Test_Ctx_RenderWithViewBind(t *testing.T) {
t.Parallel()
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})
err := c.BindVars(Map{
err := c.ViewBind(Map{
"Title": "Hello, World!",
})
require.NoError(t, err)
@ -3462,12 +3462,12 @@ func Test_Ctx_RenderWithBindVars(t *testing.T) {
require.Equal(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}
func Test_Ctx_RenderWithOverwrittenBind(t *testing.T) {
func Test_Ctx_RenderWithOverwrittenViewBind(t *testing.T) {
t.Parallel()
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})
err := c.BindVars(Map{
err := c.ViewBind(Map{
"Title": "Hello, World!",
})
require.NoError(t, err)
@ -3484,7 +3484,7 @@ func Test_Ctx_RenderWithOverwrittenBind(t *testing.T) {
require.Equal(t, "<h1>Hello from Fiber!</h1>", string(c.Response().Body()))
}
func Test_Ctx_RenderWithBindVarsLocals(t *testing.T) {
func Test_Ctx_RenderWithViewBindLocals(t *testing.T) {
t.Parallel()
app := New(Config{
PassLocalsToViews: true,
@ -3492,7 +3492,7 @@ func Test_Ctx_RenderWithBindVarsLocals(t *testing.T) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})
err := c.BindVars(Map{
err := c.ViewBind(Map{
"Title": "Hello, World!",
})
require.NoError(t, err)
@ -3528,7 +3528,7 @@ func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
require.Equal(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}
func Benchmark_Ctx_RenderWithLocalsAndBindVars(b *testing.B) {
func Benchmark_Ctx_RenderWithLocalsAndViewBind(b *testing.B) {
engine := &testTemplateEngine{}
err := engine.Load()
require.NoError(b, err)
@ -3538,7 +3538,7 @@ func Benchmark_Ctx_RenderWithLocalsAndBindVars(b *testing.B) {
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
err = c.BindVars(Map{
err = c.ViewBind(Map{
"Title": "Hello, World!",
})
require.NoError(b, err)
@ -3578,7 +3578,7 @@ func Benchmark_Ctx_RenderLocals(b *testing.B) {
require.Equal(b, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}
func Benchmark_Ctx_RenderBindVars(b *testing.B) {
func Benchmark_Ctx_RenderViewBind(b *testing.B) {
engine := &testTemplateEngine{}
err := engine.Load()
require.NoError(b, err)
@ -3586,7 +3586,7 @@ func Benchmark_Ctx_RenderBindVars(b *testing.B) {
app.config.Views = engine
c := app.AcquireCtx(&fasthttp.RequestCtx{})
err = c.BindVars(Map{
err = c.ViewBind(Map{
"Title": "Hello, World!",
})
require.NoError(b, err)

View File

@ -1,6 +1,6 @@
{
"label": "API",
"position": 2,
"label": "\uD83D\uDEE0\uFE0F API",
"position": 3,
"link": {
"type": "generated-index",
"description": "API documentation for Fiber."

View File

@ -5,9 +5,13 @@ description: The app instance conventionally denotes the Fiber application.
sidebar_position: 2
---
import Reference from '@site/src/components/reference';
## Routing
import RoutingHandler from './../partials/routing/handler.md';
## Static
### Static
Use the **Static** method to serve static files such as **images**, **CSS,** and **JavaScript**.
@ -21,17 +25,13 @@ func (app *App) Static(prefix, root string, config ...Static) Router
Use the following code to serve files in a directory named `./public`
```go
```go title="Examples"
// Serve files from multiple directories
app.Static("/", "./public")
// => http://localhost:3000/hello.html
// => http://localhost:3000/js/jquery.js
// => http://localhost:3000/css/style.css
```
```go title="Examples"
// Serve files from multiple directories
app.Static("/", "./public")
// Serve files from "./files" directory:
app.Static("/", "./files")
@ -47,55 +47,21 @@ app.Static("/static", "./public")
// => http://localhost:3000/static/css/style.css
```
#### Config
If you want to have a little bit more control regarding the settings for serving static files. You could use the `fiber.Static` struct to enable specific settings.
```go title="fiber.Static{}"
// Static defines configuration options when defining static assets.
type Static struct {
// When set to true, the server tries minimizing CPU usage by caching compressed files.
// This works differently than the github.com/gofiber/compression middleware.
// Optional. Default value false
Compress bool `json:"compress"`
// When set to true, enables byte range requests.
// Optional. Default value false
ByteRange bool `json:"byte_range"`
// When set to true, enables directory browsing.
// Optional. Default value false.
Browse bool `json:"browse"`
// When set to true, enables direct download.
// Optional. Default value false.
Download bool `json:"download"`
// The name of the index file for serving a directory.
// Optional. Default value "index.html".
Index string `json:"index"`
// Expiration duration for inactive file handlers.
// Use a negative time.Duration to disable it.
//
// Optional. Default value 10 * time.Second.
CacheDuration time.Duration `json:"cache_duration"`
// The value for the Cache-Control HTTP-header
// that is set on the file response. MaxAge is defined in seconds.
//
// Optional. Default value 0.
MaxAge int `json:"max_age"`
// ModifyResponse defines a function that allows you to alter the response.
//
// Optional. Default: nil
ModifyResponse Handler
// Next defines a function to skip this middleware when returned true.
//
// Optional. Default: nil
Next func(c Ctx) bool
}
```
| Property | Type | Description | Default |
|------------------------------------------------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
| <Reference id="compress">Compress</Reference> | `bool` | When set to true, the server tries minimizing CPU usage by caching compressed files. This works differently than the [compress](../middleware/compress.md) middleware. | false |
| <Reference id="byte_range">ByteRange</Reference> | `bool` | When set to true, enables byte range requests. | false |
| <Reference id="browse">Browse</Reference> | `bool` | When set to true, enables directory browsing. | false |
| <Reference id="download">Download</Reference> | `bool` | When set to true, enables direct download. | false |
| <Reference id="index">Index</Reference> | `string` | The name of the index file for serving a directory. | "index.html" |
| <Reference id="cache_duration">CacheDuration</Reference> | `time.Duration` | Expiration duration for inactive file handlers. Use a negative `time.Duration` to disable it. | 10 * time.Second |
| <Reference id="max_age">MaxAge</Reference> | `int` | The value for the `Cache-Control` HTTP-header that is set on the file response. MaxAge is defined in seconds. | 0 |
| <Reference id="modify_response">ModifyResponse</Reference> | `Handler` | ModifyResponse defines a function that allows you to alter the response. | nil |
| <Reference id="next">Next</Reference> | `func(c Ctx) bool` | Next defines a function to skip this middleware when returned true. | nil |
```go title="Example"
// Custom config
@ -109,23 +75,19 @@ app.Static("/", "./public", fiber.Static{
})
```
## Route Handlers
### Route Handlers
<RoutingHandler />
## Mount
### Mounting
You can Mount Fiber instance by creating a `*Mount`
```go title="Signature"
func (a *App) Mount(prefix string, app *App) Router
```
You can Mount Fiber instance using the [`app.Use`](./app.md#use) method similar to [`express`](https://expressjs.com/en/api.html#router.use).
```go title="Examples"
func main() {
app := fiber.New()
micro := fiber.New()
app.Mount("/john", micro) // GET /john/doe -> 200 OK
app.Use("/john", micro) // GET /john/doe -> 200 OK
micro.Get("/doe", func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
@ -135,7 +97,7 @@ func main() {
}
```
## MountPath
### MountPath
The `MountPath` property contains one or more path patterns on which a sub-app was mounted.
@ -150,9 +112,9 @@ func main() {
two := fiber.New()
three := fiber.New()
two.Mount("/three", three)
one.Mount("/two", two)
app.Mount("/one", one)
two.Use("/three", three)
one.Use("/two", two)
app.Use("/one", one)
one.MountPath() // "/one"
two.MountPath() // "/one/two"
@ -165,7 +127,7 @@ func main() {
Mounting order is important for MountPath. If you want to get mount paths properly, you should start mounting from the deepest app.
:::
## Group
### Group
You can group routes by creating a `*Group` struct.
@ -191,7 +153,7 @@ func main() {
}
```
## Route
### Route
You can define routes with a common prefix inside the common function.
@ -212,39 +174,7 @@ func main() {
}
```
## Server
Server returns the underlying [fasthttp server](https://godoc.org/github.com/valyala/fasthttp#Server)
```go title="Signature"
func (app *App) Server() *fasthttp.Server
```
```go title="Examples"
func main() {
app := fiber.New()
app.Server().MaxConnsPerIP = 1
// ...
}
```
## Server Shutdown
Shutdown gracefully shuts down the server without interrupting any active connections. Shutdown works by first closing all open listeners and then waits indefinitely for all connections to return to idle before shutting down.
ShutdownWithTimeout will forcefully close any active connections after the timeout expires.
ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded.
```go
func (app *App) Shutdown() error
func (app *App) ShutdownWithTimeout(timeout time.Duration) error
func (app *App) ShutdownWithContext(ctx context.Context) error
```
## HandlersCount
### HandlersCount
This method returns the amount of registered handlers.
@ -252,7 +182,7 @@ This method returns the amount of registered handlers.
func (app *App) HandlersCount() uint32
```
## Stack
### Stack
This method returns the original router stack
@ -276,7 +206,10 @@ func main() {
}
```
```javascript title="Result"
<details>
<summary>Click here to see the result</summary>
```json
[
[
{
@ -305,8 +238,9 @@ func main() {
]
]
```
</details>
## Name
### Name
This method assigns the name of latest created route.
@ -342,7 +276,10 @@ func main() {
}
```
```javascript title="Result"
<details>
<summary>Click here to see the result</summary>
```json
[
[
{
@ -407,8 +344,9 @@ func main() {
null
]
```
</details>
## GetRoute
### GetRoute
This method gets the route by name.
@ -429,11 +367,13 @@ func main() {
app.Listen(":3000")
}
```
```javascript title="Result"
<details>
<summary>Click here to see the result</summary>
```json
{
"method": "GET",
"name": "index",
@ -441,8 +381,9 @@ func main() {
"params": null
}
```
</details>
## GetRoutes
### GetRoutes
This method gets all routes.
@ -462,7 +403,10 @@ func main() {
}
```
```javascript title="Result"
<details>
<summary>Click here to see the result</summary>
```json
[
{
"method": "POST",
@ -472,10 +416,11 @@ func main() {
}
]
```
</details>
## Config
Config returns the app config as value \( read-only \).
Config returns the [app config](./fiber.md#config) as value \( read-only \).
```go title="Signature"
func (app *App) Config() Config
@ -483,138 +428,103 @@ func (app *App) Config() Config
## Handler
Handler returns the server handler that can be used to serve custom \*fasthttp.RequestCtx requests.
Handler returns the server handler that can be used to serve custom [`\*fasthttp.RequestCtx`](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) requests.
```go title="Signature"
func (app *App) Handler() fasthttp.RequestHandler
```
## Listen
## ErrorHandler
Listen serves HTTP requests from the given address.
Errorhandler executes the process which was defined for the application in case of errors, this is used in some cases in middlewares.
```go title="Signature"
func (app *App) Listen(addr string) error
func (app *App) ErrorHandler(ctx Ctx, err error) error
```
## NewCtxFunc
NewCtxFunc allows to customize the ctx struct as we want.
```go title="Signature"
func (app *App) NewCtxFunc(function func(app *App) CustomCtx)
```
```go title="Examples"
// Listen on port :8080
app.Listen(":8080")
// Custom host
app.Listen("127.0.0.1:8080")
```
## ListenTLS
ListenTLS serves HTTPs requests from the given address using certFile and keyFile paths to as TLS certificate and key file.
```go title="Signature"
func (app *App) ListenTLS(addr, certFile, keyFile string) error
```
```go title="Examples"
app.ListenTLS(":443", "./cert.pem", "./cert.key");
```
Using `ListenTLS` defaults to the following config \( use `Listener` to provide your own config \)
```go title="Default \*tls.Config"
&tls.Config{
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{
cert,
},
type CustomCtx struct {
DefaultCtx
}
```
## ListenTLSWithCertificate
```go title="Signature"
func (app *App) ListenTLS(addr string, cert tls.Certificate) error
```
```go title="Examples"
app.ListenTLSWithCertificate(":443", cert);
```
Using `ListenTLSWithCertificate` defaults to the following config \( use `Listener` to provide your own config \)
```go title="Default \*tls.Config"
&tls.Config{
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{
cert,
},
// Custom method
func (c *CustomCtx) Params(key string, defaultValue ...string) string {
return "prefix_" + c.DefaultCtx.Params(key)
}
app := New()
app.NewCtxFunc(func(app *fiber.App) fiber.CustomCtx {
return &CustomCtx{
DefaultCtx: *NewDefaultCtx(app),
}
})
// curl http://localhost:3000/123
app.Get("/:id", func(c Ctx) error {
// use custom method - output: prefix_123
return c.SendString(c.Params("id"))
})
```
## ListenMutualTLS
## RegisterCustomBinder
ListenMutualTLS serves HTTPs requests from the given address using certFile, keyFile and clientCertFile are the paths to TLS certificate and key file
You can register custom binders to use as [`Bind().Custom("name")`](bind.md#custom).
They should be compatible with CustomBinder interface.
```go title="Signature"
func (app *App) ListenMutualTLS(addr, certFile, keyFile, clientCertFile string) error
func (app *App) RegisterCustomBinder(binder CustomBinder)
```
```go title="Examples"
app.ListenMutualTLS(":443", "./cert.pem", "./cert.key", "./ca-chain-cert.pem");
```
app := fiber.New()
Using `ListenMutualTLS` defaults to the following config \( use `Listener` to provide your own config \)
```go title="Default \*tls.Config"
&tls.Config{
MinVersion: tls.VersionTLS12,
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: clientCertPool,
Certificates: []tls.Certificate{
cert,
},
// My custom binder
customBinder := &customBinder{}
// Name of custom binder, which will be used as Bind().Custom("name")
func (*customBinder) Name() string {
return "custom"
}
```
## ListenMutualTLSWithCertificate
ListenMutualTLSWithCertificate serves HTTPs requests from the given address using certFile, keyFile and clientCertFile are the paths to TLS certificate and key file
```go title="Signature"
func (app *App) ListenMutualTLSWithCertificate(addr string, cert tls.Certificate, clientCertPool *x509.CertPool) error
```
```go title="Examples"
app.ListenMutualTLSWithCertificate(":443", cert, clientCertPool);
```
Using `ListenMutualTLSWithCertificate` defaults to the following config \( use `Listener` to provide your own config \)
```go title="Default \*tls.Config"
&tls.Config{
MinVersion: tls.VersionTLS12,
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: clientCertPool,
Certificates: []tls.Certificate{
cert,
},
// Is used in the Body Bind method to check if the binder should be used for custom mime types
func (*customBinder) MIMETypes() []string {
return []string{"application/yaml"}
}
```
// Parse the body and bind it to the out interface
func (*customBinder) Parse(c Ctx, out any) error {
// parse yaml body
return yaml.Unmarshal(c.Body(), out)
}
// Register custom binder
app.RegisterCustomBinder(customBinder)
## Listener
You can pass your own [`net.Listener`](https://pkg.go.dev/net/#Listener) using the `Listener` method. This method can be used to enable **TLS/HTTPS** with a custom tls.Config.
```go title="Signature"
func (app *App) Listener(ln net.Listener) error
```
```go title="Examples"
ln, _ := net.Listen("tcp", ":3000")
cer, _:= tls.LoadX509KeyPair("server.crt", "server.key")
ln = tls.NewListener(ln, &tls.Config{Certificates: []tls.Certificate{cer}})
app.Listener(ln)
// curl -X POST http://localhost:3000/custom -H "Content-Type: application/yaml" -d "name: John"
app.Post("/custom", func(c Ctx) error {
var user User
// output: {Name:John}
// Custom binder is used by the name
if err := c.Bind().Custom("custom", &user); err != nil {
return err
}
// ...
return c.JSON(user)
})
// curl -X POST http://localhost:3000/normal -H "Content-Type: application/yaml" -d "name: Doe"
app.Post("/normal", func(c Ctx) error {
var user User
// output: {Name:Doe}
// Custom binder is used by the mime type
if err := c.Bind().Body(&user); err != nil {
return err
}
// ...
return c.JSON(user)
})
```
## RegisterCustomConstraint
@ -627,6 +537,15 @@ func (app *App) RegisterCustomConstraint(constraint CustomConstraint)
See [Custom Constraint](../guide/routing.md#custom-constraint) section for more information.
## SetTLSHandler
Use SetTLSHandler to set [ClientHelloInfo](https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2) when using TLS with Listener.
```go title="Signature"
func (app *App) SetTLSHandler(tlsHandler *TLSHandler)
```
## Test
Testing your application is done with the **Test** method. Use this method for creating `_test.go` files or when you need to debug your routing logic. The default timeout is `1s` if you want to disable a timeout altogether, pass `-1` as a second argument.
@ -660,8 +579,8 @@ if resp.StatusCode == fiber.StatusOK {
## Hooks
Hooks is a method to return [hooks](../guide/hooks.md) property.
Hooks is a method to return [hooks](./hooks.md) property.
```go title="Signature"
func (app *App) Hooks() *Hooks
```
```

590
docs/api/bind.md Normal file
View File

@ -0,0 +1,590 @@
---
id: bind
title: 📎 Bind
description: Binds the request and response items to a struct.
sidebar_position: 4
toc_max_heading_level: 4
---
Bindings are used to parse the request/response body, query parameters, cookies and much more into a struct.
:::info
All binder returned value are only valid within the handler. Do not store any references.
Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more...](../#zero-allocation)
:::
## Binders
- [Body](#body)
- [Form](#form)
- [JSON](#json)
- [MultipartForm](#multipartform)
- [XML](#xml)
- [Cookie](#cookie)
- [Header](#header)
- [Query](#query)
- [RespHeader](#respheader)
- [URI](#uri)
### Body
Binds the request body to a struct.
It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a JSON body with a field called Pass, you would use a struct field of `json:"pass"`.
| content-type | struct tag |
| ----------------------------------- | ---------- |
| `application/x-www-form-urlencoded` | form |
| `multipart/form-data` | form |
| `application/json` | json |
| `application/xml` | xml |
| `text/xml` | xml |
```go title="Signature"
func (b *Bind) Body(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `json:"name" xml:"name" form:"name"`
Pass string `json:"pass" xml:"pass" form:"pass"`
}
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().Body(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000
// curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000
// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000
// curl -X POST -F name=john -F pass=doe http://localhost:3000
// curl -X POST "http://localhost:3000/?name=john&pass=doe"
```
**The methods for the various bodies can also be used directly:**
#### Form
Binds the request form body to a struct.
It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a Form body with a field called Pass, you would use a struct field of `form:"pass"`.
```go title="Signature"
func (b *Bind) Form(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `form:"name"`
Pass string `form:"pass"`
}
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().Form(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000
```
#### JSON
Binds the request json body to a struct.
It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a JSON body with a field called Pass, you would use a struct field of `json:"pass"`.
```go title="Signature"
func (b *Bind) JSON(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `json:"name"`
Pass string `json:"pass"`
}
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().JSON(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000
```
#### MultipartForm
Binds the request multipart form body to a struct.
It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a MultipartForm body with a field called Pass, you would use a struct field of `form:"pass"`.
```go title="Signature"
func (b *Bind) MultipartForm(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `form:"name"`
Pass string `form:"pass"`
}
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().MultipartForm(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: multipart/form-data" -F "name=john" -F "pass=doe" localhost:3000
```
#### XML
Binds the request xml form body to a struct.
It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a XML body with a field called Pass, you would use a struct field of `xml:"pass"`.
```go title="Signature"
func (b *Bind) XML(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `xml:"name"`
Pass string `xml:"pass"`
}
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().XML(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000
```
### Cookie
This method is similar to [Body-Binding](#body), but for cookie parameters.
It is important to use the struct tag "cookie". For example, if you want to parse a cookie with a field called Age, you would use a struct field of `cookie:"age"`.
```go title="Signature"
func (b *Bind) Cookie(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `cookie:"name"`
Age int `cookie:"age"`
Job bool `cookie:"job"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().Cookie(p); err != nil {
return err
}
log.Println(p.Name) // Joseph
log.Println(p.Age) // 23
log.Println(p.Job) // true
})
// Run tests with the following curl command
// curl.exe --cookie "name=Joseph; age=23; job=true" http://localhost:8000/
```
### Header
This method is similar to [Body-Binding](#body), but for request headers.
It is important to use the struct tag "header". For example, if you want to parse a request header with a field called Pass, you would use a struct field of `header:"pass"`.
```go title="Signature"
func (b *Bind) Header(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `header:"name"`
Pass string `header:"pass"`
Products []string `header:"products"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().Header(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
log.Println(p.Products) // [shoe, hat]
// ...
})
// Run tests with the following curl command
// curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat"
```
### Query
This method is similar to [Body-Binding](#body), but for query parameters.
It is important to use the struct tag "query". For example, if you want to parse a query parameter with a field called Pass, you would use a struct field of `query:"pass"`.
```go title="Signature"
func (b *Bind) Query(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `query:"name"`
Pass string `query:"pass"`
Products []string `query:"products"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().Query(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// fiber.Config{EnableSplittingOnParsers: false} - default
log.Println(p.Products) // ["shoe,hat"]
// fiber.Config{EnableSplittingOnParsers: true}
// log.Println(p.Products) // ["shoe", "hat"]
// ...
})
// Run tests with the following curl command
// curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat"
```
:::info
For more parser settings please look here [Config](fiber.md#enablesplittingonparsers)
:::
### RespHeader
This method is similar to [Body-Binding](#body), but for response headers.
It is important to use the struct tag "respHeader". For example, if you want to parse a request header with a field called Pass, you would use a struct field of `respHeader:"pass"`.
```go title="Signature"
func (b *Bind) Header(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `respHeader:"name"`
Pass string `respHeader:"pass"`
Products []string `respHeader:"products"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().RespHeader(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
log.Println(p.Products) // [shoe, hat]
// ...
})
// Run tests with the following curl command
// curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat"
```
### URI
This method is similar to [Body-Binding](#body), but for path parameters. It is important to use the struct tag "uri". For example, if you want to parse a path parameter with a field called Pass, you would use a struct field of uri:"pass"
```go title="Signature"
func (b *Bind) URI(out any) error
```
```go title="Example"
// GET http://example.com/user/111
app.Get("/user/:id", func(c fiber.Ctx) error {
param := struct {ID uint `uri:"id"`}{}
c.Bind().URI(&param) // "{"id": 111}"
// ...
})
```
## Custom
To use custom binders, you have to use this method.
You can register them from [RegisterCustomBinder](./app.md#registercustombinder) method of Fiber instance.
```go title="Signature"
func (b *Bind) Custom(name string, dest any) error
```
```go title="Example"
app := fiber.New()
// My custom binder
customBinder := &customBinder{}
// Name of custom binder, which will be used as Bind().Custom("name")
func (*customBinder) Name() string {
return "custom"
}
// Is used in the Body Bind method to check if the binder should be used for custom mime types
func (*customBinder) MIMETypes() []string {
return []string{"application/yaml"}
}
// Parse the body and bind it to the out interface
func (*customBinder) Parse(c Ctx, out any) error {
// parse yaml body
return yaml.Unmarshal(c.Body(), out)
}
// Register custom binder
app.RegisterCustomBinder(customBinder)
// curl -X POST http://localhost:3000/custom -H "Content-Type: application/yaml" -d "name: John"
app.Post("/custom", func(c Ctx) error {
var user User
// output: {Name:John}
// Custom binder is used by the name
if err := c.Bind().Custom("custom", &user); err != nil {
return err
}
// ...
return c.JSON(user)
})
```
Internally they are also used in the [Body](#body) method.
For this the MIMETypes method is used to check if the custom binder should be used for the given content type.
## Options
For more control over the error handling, you can use the following methods.
### Must
If you want to handle binder errors automatically, you can use Must.
If there's an error it'll return error and 400 as HTTP status.
```go title="Signature"
func (b *Bind) Must() *Bind
```
### Should
To handle binder errors manually, you can prefer Should method.
It's default behavior of binder.
```go title="Signature"
func (b *Bind) Should() *Bind
```
## SetParserDecoder
Allow you to config BodyParser/QueryParser decoder, base on schema's options, providing possibility to add custom type for parsing.
```go title="Signature"
func SetParserDecoder(parserConfig fiber.ParserConfig{
IgnoreUnknownKeys bool,
ParserType []fiber.ParserType{
Customtype any,
Converter func(string) reflect.Value,
},
ZeroEmpty bool,
SetAliasTag string,
})
```
```go title="Example"
type CustomTime time.Time
// String() returns the time in string
func (ct *CustomTime) String() string {
t := time.Time(*ct).String()
return t
}
// Register the converter for CustomTime type format as 2006-01-02
var timeConverter = func(value string) reflect.Value {
fmt.Println("timeConverter", value)
if v, err := time.Parse("2006-01-02", value); err == nil {
return reflect.ValueOf(v)
}
return reflect.Value{}
}
customTime := fiber.ParserType{
Customtype: CustomTime{},
Converter: timeConverter,
}
// Add setting to the Decoder
fiber.SetParserDecoder(fiber.ParserConfig{
IgnoreUnknownKeys: true,
ParserType: []fiber.ParserType{customTime},
ZeroEmpty: true,
})
// Example to use CustomType, you pause custom time format not in RFC3339
type Demo struct {
Date CustomTime `form:"date" query:"date"`
Title string `form:"title" query:"title"`
Body string `form:"body" query:"body"`
}
app.Post("/body", func(c fiber.Ctx) error {
var d Demo
c.BodyParser(&d)
fmt.Println("d.Date", d.Date.String())
return c.JSON(d)
})
app.Get("/query", func(c fiber.Ctx) error {
var d Demo
c.QueryParser(&d)
fmt.Println("d.Date", d.Date.String())
return c.JSON(d)
})
// curl -X POST -F title=title -F body=body -F date=2021-10-20 http://localhost:3000/body
// curl -X GET "http://localhost:3000/query?title=title&body=body&date=2021-10-20"
```
## Validation
Validation is also possible with the binding methods. You can specify your validation rules using the `validate` struct tag.
Specify your struct validator in the [config](./fiber.md#structvalidator)
Setup your validator in the config:
```go title="Example"
import "github.com/go-playground/validator/v10"
type structValidator struct {
validate *validator.Validate
}
// Validator needs to implement the Validate method
func (v *structValidator) Validate(out any) error {
return v.validate.Struct(out)
}
// Setup your validator in the config
app := fiber.New(fiber.Config{
StructValidator: &structValidator{validate: validator.New()},
})
```
Usage of the validation in the binding methods:
```go title="Example"
type Person struct {
Name string `json:"name" validate:"required"`
Age int `json:"age" validate:"gte=18,lte=60"`
}
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.Bind().JSON(p); err != nil {// <- here you receive the validation errors
return err
}
})
```

View File

@ -2,7 +2,7 @@
id: client
title: 🌎 Client
description: The Client struct represents the Fiber HTTP Client.
sidebar_position: 5
sidebar_position: 6
---
## Start request
@ -537,7 +537,8 @@ agent.SetResponse(resp)
ReleaseResponse(resp)
```
<details><summary>Example handling for response values</summary>
<details>
<summary>Example handling for response values</summary>
```go title="Example handling response"
// Create a Fiber HTTP client agent

View File

@ -2,10 +2,10 @@
id: constants
title: 📋 Constants
description: Some constants for Fiber.
sidebar_position: 4
sidebar_position: 9
---
HTTP methods were copied from net/http.
### HTTP methods were copied from net/http.
```go
const (
@ -22,7 +22,7 @@ const (
)
```
MIME types that are commonly used
### MIME types that are commonly used
```go
const (
@ -45,7 +45,7 @@ const (
)
```
HTTP status codes were copied from net/http.
### HTTP status codes were copied from net/http.
```go
const (
@ -114,7 +114,7 @@ const (
)
```
Errors
### Errors
```go
var (
@ -288,4 +288,4 @@ const (
HeaderXRobotsTag = "X-Robots-Tag"
HeaderXUACompatible = "X-UA-Compatible"
)
```
```

View File

@ -100,31 +100,6 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## AllParams
Params is used to get all route parameters.
Using Params method to get params.
```go title="Signature"
func (c Ctx) AllParams() map[string]string
```
```go title="Example"
// GET http://example.com/user/fenny
app.Get("/user/:name", func(c fiber.Ctx) error {
c.AllParams() // "{"name": "fenny"}"
// ...
})
// GET http://example.com/user/fenny/123
app.Get("/user/*", func(c fiber.Ctx) error {
c.AllParams() // "{"*1": "fenny/123"}"
// ...
})
```
## App
Returns the [\*App](ctx.md) reference so you could easily access all application settings.
@ -244,45 +219,23 @@ app.Get("/", func(c fiber.Ctx) error {
## Bind
Add vars to default view var map binding to template engine.
Variables are read by the Render method and may be overwritten.
Bind is a method that support 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 Ctx) Bind(vars Map) error
func (c Ctx) Bind() *Bind
```
```go title="Example"
app.Use(func(c fiber.Ctx) error {
c.Bind(fiber.Map{
"Title": "Hello, World!",
})
})
app.Get("/", func(c fiber.Ctx) error {
return c.Render("xxx.tmpl", fiber.Map{}) // Render will use Title variable
})
```
## BodyRaw
Returns the raw request **body**.
```go title="Signature"
func (c 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")
user := new(User)
// Bind the request body to a struct:
return c.Bind().Body(user)
})
```
> _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)
## Body
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).
@ -300,62 +253,36 @@ app.Post("/", func(c fiber.Ctx) error {
})
```
> _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)
:::info
## BodyParser
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)
Binds the request body to a struct.
:::
It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a JSON body with a field called Pass, you would use a struct field of `json:"pass"`.
## BodyRaw
| content-type | struct tag |
| ----------------------------------- | ---------- |
| `application/x-www-form-urlencoded` | form |
| `multipart/form-data` | form |
| `application/json` | json |
| `application/xml` | xml |
| `text/xml` | xml |
Returns the raw request **body**.
```go title="Signature"
func (c Ctx) BodyParser(out any) error
func (c Ctx) BodyRaw() []byte
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `json:"name" xml:"name" form:"name"`
Pass string `json:"pass" xml:"pass" form:"pass"`
}
// curl -X POST http://localhost:8080 -d user=john
app.Post("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.BodyParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
// Get raw body from POST request:
return c.Send(c.BodyRaw()) // []byte("user=john")
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000
// curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000
// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000
// curl -X POST -F name=john -F pass=doe http://localhost:3000
// curl -X POST "http://localhost:3000/?name=john&pass=doe"
```
> _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)
:::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)
:::
## ClearCookie
@ -475,38 +402,6 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## CookieParser
This method is similar to [BodyParser](ctx.md#bodyparser), but for cookie parameters.
It is important to use the struct tag "cookie". For example, if you want to parse a cookie with a field called Age, you would use a struct field of `cookie:"age"`.
```go title="Signature"
func (c Ctx) CookieParser(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `cookie:"name"`
Age int `cookie:"age"`
Job bool `cookie:"job"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.CookieParser(p); err != nil {
return err
}
log.Println(p.Name) // Joseph
log.Println(p.Age) // 23
log.Println(p.Job) // true
})
// Run tests with the following curl command
// curl.exe --cookie "name=Joseph; age=23; job=true" http://localhost:8000/
```
## Cookies
Get cookie value by key, you could pass an optional default value that will be returned if the cookie key does not exist.
@ -524,8 +419,12 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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)
:::
## Download
@ -638,8 +537,12 @@ app.Post("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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
@ -674,8 +577,12 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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
@ -685,8 +592,12 @@ Returns the HTTP request headers as a map. Since a header can be set multiple ti
func (c Ctx) GetReqHeaders() map[string][]string
```
> _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)
:::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)
:::
## GetRespHeader
@ -709,8 +620,12 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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)
:::
## GetRespHeaders
@ -720,8 +635,12 @@ Returns the HTTP response headers as a map. Since a header can be set multiple t
func (c Ctx) GetRespHeaders() map[string][]string
```
> _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)
:::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)
:::
## GetRouteURL
@ -748,6 +667,34 @@ app.Get("/test", func(c fiber.Ctx) error {
// /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.
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 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.
@ -766,8 +713,12 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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
@ -785,7 +736,7 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
When registering the proxy request header in the fiber app, the ip address of the header is returned [(Fiber configuration)](fiber.md#config)
When registering the proxy request header in the fiber app, the ip address of the header is returned [(Fiber configuration)](fiber.md#proxyheader)
```go
app := fiber.New(fiber.Config{
@ -857,6 +808,35 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## IsProxyTrusted
Checks trustworthiness of remote ip.
If [`EnableTrustedProxyCheck`](fiber.md#enabletrustedproxycheck) false, it returns true
IsProxyTrusted can check remote ip by proxy ranges and ip map.
```go title="Signature"
func (c Ctx) IsProxyTrusted() bool
```
```go title="Example"
app := fiber.New(fiber.Config{
// EnableTrustedProxyCheck enables the trusted proxy check
EnableTrustedProxyCheck: true,
// TrustedProxies is a list of trusted proxy IP addresses
TrustedProxies: []string{"0.8.0.0", "0.8.0.1"},
})
app.Get("/", func(c fiber.Ctx) error {
// If request came from trusted proxy, return true else return false
c.IsProxyTrusted()
// ...
})
```
## JSON
Converts any **interface** or **string** to JSON using the [encoding/json](https://pkg.go.dev/encoding/json) package.
@ -1145,8 +1125,12 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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
@ -1194,8 +1178,12 @@ app.Get("/v1/*/shop/*", func(c fiber.Ctx) error {
})
```
> _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)
:::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)
:::
In certain scenarios, it can be useful to have an alternative approach to handle different types of parameters, not
@ -1225,25 +1213,6 @@ The generic Params function supports returning the following data types based on
- String: string
- Byte array: []byte
## ParamsParser
This method is similar to BodyParser, but for path parameters. It is important to use the struct tag "params". For example, if you want to parse a path parameter with a field called Pass, you would use a struct field of params:"pass"
```go title="Signature"
func (c Ctx) ParamsParser(out any) error
```
```go title="Example"
// GET http://example.com/user/111
app.Get("/user/:id", func(c fiber.Ctx) error {
param := struct {ID uint `params:"id"`}{}
c.ParamsParser(&param) // "{"id": 111}"
// ...
})
```
## Path
@ -1266,6 +1235,23 @@ app.Get("/users", func(c fiber.Ctx) error {
})
```
## Port
Returns the remote port of the request.
```go title="Signature"
func (c Ctx) Port() string
```
```go title="Example"
// GET http://example.com:8080
app.Get("/", func(c fiber.Ctx) error {
c.Port() // "8080"
// ...
})
```
## Protocol
Contains the request protocol string: `http` or `https` for **TLS** requests.
@ -1372,8 +1358,12 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
> _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)
:::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)
:::
In certain scenarios, it can be useful to have an alternative approach to handle different types of query parameters, not
just strings. This can be achieved using a generic Query function known as `Query[V GenericType](c Ctx, key string, defaultValue ...V) V`.
@ -1412,49 +1402,6 @@ The generic Query function supports returning the following data types based on
- String: string
- Byte array: []byte
## QueryParser
This method is similar to [BodyParser](ctx.md#bodyparser), but for query parameters.
It is important to use the struct tag "query". For example, if you want to parse a query parameter with a field called Pass, you would use a struct field of `query:"pass"`.
```go title="Signature"
func (c Ctx) QueryParser(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `query:"name"`
Pass string `query:"pass"`
Products []string `query:"products"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.QueryParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// fiber.Config{EnableSplittingOnParsers: false} - default
log.Println(p.Products) // ["shoe,hat"]
// fiber.Config{EnableSplittingOnParsers: true}
// log.Println(p.Products) // ["shoe", "hat"]
// ...
})
// Run tests with the following curl command
// curl "http://localhost:3000/?name=john&pass=doe&products=shoe,hat"
```
:::info
For more parser settings please look here [Config](fiber.md#config)
:::
## Range
A struct containing the type and a slice of ranges will be returned.
@ -1478,104 +1425,31 @@ app.Get("/", func(c fiber.Ctx) error {
## Redirect
Redirects to the URL derived from the specified path, with specified status, a positive integer that corresponds to an HTTP status code.
Returns the Redirect reference.
:::info
If **not** specified, status defaults to **302 Found**.
:::
For detailed information check the [Redirect](./redirect.md) documentation.
```go title="Signature"
func (c Ctx) Redirect(location string, status ...int) error
func (c Ctx) Redirect() *Redirect
```
```go title="Example"
app.Get("/coffee", func(c fiber.Ctx) error {
return c.Redirect("/teapot")
return c.Redirect().To("/teapot")
})
app.Get("/teapot", func(c fiber.Ctx) error {
return c.Status(fiber.StatusTeapot).Send("🍵 short and stout 🍵")
return c.Status(fiber.StatusTeapot).Send("🍵 short and stout 🍵")
})
```
```go title="More examples"
app.Get("/", func(c fiber.Ctx) error {
return c.Redirect("/foo/bar")
return c.Redirect("../login")
return c.Redirect("http://example.com")
return c.Redirect("http://example.com", 301)
})
```
## RedirectToRoute
Redirects to the specific route along with the parameters and with specified status, a positive integer that corresponds to an HTTP status code.
:::info
If **not** specified, status defaults to **302 Found**.
:::
:::info
If you want to send queries to route, you must add **"queries"** key typed as **map[string]string** to params.
:::
```go title="Signature"
func (c Ctx) RedirectToRoute(routeName string, params fiber.Map, status ...int) error
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
// /user/fiber
return c.RedirectToRoute("user", fiber.Map{
"name": "fiber"
})
})
app.Get("/with-queries", func(c fiber.Ctx) error {
// /user/fiber?data[0][name]=john&data[0][age]=10&test=doe
return c.RedirectToRoute("user", fiber.Map{
"name": "fiber",
"queries": map[string]string{"data[0][name]": "john", "data[0][age]": "10", "test": "doe"},
})
})
app.Get("/user/:name", func(c fiber.Ctx) error {
return c.SendString(c.Params("name"))
}).Name("user")
```
## RedirectBack
Redirects back to refer URL. It redirects to fallback URL if refer header doesn't exists, with specified status, a positive integer that corresponds to an HTTP status code.
:::info
If **not** specified, status defaults to **302 Found**.
:::
```go title="Signature"
func (c Ctx) RedirectBack(fallback string, status ...int) error
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Home page")
})
app.Get("/test", func(c fiber.Ctx) error {
c.Set("Content-Type", "text/html")
return c.SendString(`<a href="/back">Back</a>`)
})
app.Get("/back", func(c fiber.Ctx) error {
return c.RedirectBack("/")
})
```
## Render
Renders a view with data and sends a `text/html` response. By default `Render` uses the default [**Go Template engine**](https://pkg.go.dev/html/template/). If you want to use another View engine, please take a look at our [**Template middleware**](https://docs.gofiber.io/template).
```go title="Signature"
func (c Ctx) Render(name string, bind any, layouts ...string) error
func (c Ctx) Render(name string, bind Map, layouts ...string) error
```
## Request
@ -1593,41 +1467,6 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## ReqHeaderParser
This method is similar to [BodyParser](ctx.md#bodyparser), but for request headers.
It is important to use the struct tag "reqHeader". For example, if you want to parse a request header with a field called Pass, you would use a struct field of `reqHeader:"pass"`.
```go title="Signature"
func (c Ctx) ReqHeaderParser(out any) error
```
```go title="Example"
// Field names should start with an uppercase letter
type Person struct {
Name string `reqHeader:"name"`
Pass string `reqHeader:"pass"`
Products []string `reqHeader:"products"`
}
app.Get("/", func(c fiber.Ctx) error {
p := new(Person)
if err := c.ReqHeaderParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
log.Println(p.Products) // [shoe, hat]
// ...
})
// Run tests with the following curl command
// curl "http://localhost:3000/" -H "name: john" -H "pass: doe" -H "products: shoe,hat"
```
## Response
Response return the [\*fasthttp.Response](https://godoc.org/github.com/valyala/fasthttp#Response) pointer
@ -1644,6 +1483,16 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## Reset
Reset the context fields by given request when to use server handlers.
```go title="Signature"
func (c 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.
@ -1767,6 +1616,27 @@ app.Post("/", func(c fiber.Ctx) error {
})
```
## Schema
Contains the request protocol string: http or https for TLS requests.
:::info
Please use [`Config.EnableTrustedProxyCheck`](fiber.md#enabletrustedproxycheck) to prevent header spoofing, in case when your app is behind the proxy.
:::
```go title="Signature"
func (c 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.
@ -1847,7 +1717,7 @@ app.Get("/file-with-url-chars", func(c fiber.Ctx) error {
```
:::info
For sending files from embedded file system [this functionality](./middleware/filesystem.md#sendfile) can be used
For sending files from embedded file system [this functionality](../middleware/filesystem.md#sendfile) can be used
:::
## SendStatus
@ -1873,6 +1743,36 @@ app.Get("/not-found", func(c fiber.Ctx) error {
})
```
## SendStream
Sets response body to a stream of data and add optional body size.
```go title="Signature"
func (c Ctx) SendStream(stream io.Reader, size ...int) error
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
return c.SendStream(bytes.NewReader([]byte("Hello, World!")))
// => "Hello, World!"
})
```
## SendString
Sets the response body to a string.
```go title="Signature"
func (c Ctx) SendString(body string) error
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello, World!")
// => "Hello, World!"
})
```
## Set
Sets the responses HTTP header field to the specified `key`, `value`.
@ -1890,80 +1790,6 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## SetParserDecoder
Allow you to config BodyParser/QueryParser decoder, base on schema's options, providing possibility to add custom type for parsing.
```go title="Signature"
func SetParserDecoder(parserConfig fiber.ParserConfig{
IgnoreUnknownKeys bool,
ParserType []fiber.ParserType{
Customtype any,
Converter func(string) reflect.Value,
},
ZeroEmpty bool,
SetAliasTag string,
})
```
```go title="Example"
type CustomTime time.Time
// String() returns the time in string
func (ct *CustomTime) String() string {
t := time.Time(*ct).String()
return t
}
// Register the converter for CustomTime type format as 2006-01-02
var timeConverter = func(value string) reflect.Value {
fmt.Println("timeConverter", value)
if v, err := time.Parse("2006-01-02", value); err == nil {
return reflect.ValueOf(v)
}
return reflect.Value{}
}
customTime := fiber.ParserType{
Customtype: CustomTime{},
Converter: timeConverter,
}
// Add setting to the Decoder
fiber.SetParserDecoder(fiber.ParserConfig{
IgnoreUnknownKeys: true,
ParserType: []fiber.ParserType{customTime},
ZeroEmpty: true,
})
// Example to use CustomType, you pause custom time format not in RFC3339
type Demo struct {
Date CustomTime `form:"date" query:"date"`
Title string `form:"title" query:"title"`
Body string `form:"body" query:"body"`
}
app.Post("/body", func(c fiber.Ctx) error {
var d Demo
c.BodyParser(&d)
fmt.Println("d.Date", d.Date.String())
return c.JSON(d)
})
app.Get("/query", func(c fiber.Ctx) error {
var d Demo
c.QueryParser(&d)
fmt.Println("d.Date", d.Date.String())
return c.JSON(d)
})
// curl -X POST -F title=title -F body=body -F date=2021-10-20 http://localhost:3000/body
// curl -X GET "http://localhost:3000/query?title=title&body=body&date=2021-10-20"
```
## SetUserContext
Sets the user specified implementation for context interface.
@ -2017,6 +1843,22 @@ app.Get("/world", func(c fiber.Ctx) error {
})
```
## String
Returns unique string representation of the ctx.
```go title="Signature"
func (c 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 string slice of subdomains in the domain name of the request.
@ -2042,6 +1884,10 @@ app.Get("/", func(c fiber.Ctx) error {
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**.
:::info
Method is a **chainable**.
:::
```go title="Signature"
func (c Ctx) Type(ext string, charset ...string) Ctx
```
@ -2103,6 +1949,27 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## ViewBind
Add vars to default view var map binding to template engine.
Variables are read by the Render method and may be overwritten.
```go title="Signature"
func (c Ctx) ViewBind(vars Map) error
```
```go title="Example"
app.Use(func(c fiber.Ctx) error {
c.ViewBind(fiber.Map{
"Title": "Hello, World!",
})
})
app.Get("/", func(c fiber.Ctx) error {
return c.Render("xxx.tmpl", fiber.Map{}) // Render will use Title variable
})
```
## Write
Write adopts the Writer interface
@ -2203,26 +2070,3 @@ app.Get("/", func(c fiber.Ctx) error {
// </Fiber>
})
```
## Convert
Converts a string value to a specified type, handling errors and optional default values.
This function simplifies the conversion process by encapsulating error handling and the management of default values, making your code cleaner and more consistent.
```go title="Signature"
func Convert[T any](value string, convertor func(string) (T, error), defaultValue ...T) (*T, error)
```
```go title="Example"
// GET http://example.com/id/bb70ab33-d455-4a03-8d78-d3c1dacae9ff
app.Get("/id/:id", func(c fiber.Ctx) error {
fiber.Convert(c.Params("id"), uuid.Parse) // UUID(bb70ab33-d455-4a03-8d78-d3c1dacae9ff), nil
// GET http://example.com/search?id=65f6f54221fb90e6a6b76db7
app.Get("/search", func(c fiber.Ctx) error) {
fiber.Convert(c.Query("id"), mongo.ParseObjectID) // objectid(65f6f54221fb90e6a6b76db7), nil
fiber.Convert(c.Query("id"), uuid.Parse) // uuid.Nil, error(cannot parse given uuid)
fiber.Convert(c.Query("id"), uuid.Parse, mongo.NewObjectID) // new object id generated and return nil as error.
}
// ...
})

View File

@ -5,9 +5,13 @@ description: Fiber represents the fiber package where you start to create an ins
sidebar_position: 1
---
## New
import Reference from '@site/src/components/reference';
This method creates a new **App** named instance. You can pass optional [config ](#config)when creating a new instance.
## Server start
### New
This method creates a new **App** named instance. You can pass optional [config](#config) when creating a new instance.
```go title="Signature"
func New(config ...Config) *App
@ -20,14 +24,13 @@ app := fiber.New()
// ...
```
## Config
### Config
You can pass an optional Config when creating a new Fiber instance.
```go title="Example"
// Custom config
app := fiber.New(fiber.Config{
Prefork: true,
CaseSensitive: true,
StrictRouting: true,
ServerHeader: "Fiber",
@ -37,52 +40,185 @@ app := fiber.New(fiber.Config{
// ...
```
**Config fields**
#### Config fields
| Property | Type | Description | Default |
| ---------------------------- | --------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --------------------- |
| AppName | `string` | This allows to setup app name for the app | `""` |
| BodyLimit | `int` | Sets the maximum allowed size for a request body, if the size exceeds the configured limit, it sends `413 - Request Entity Too Large` response. | `4 * 1024 * 1024` |
| CaseSensitive | `bool` | When enabled, `/Foo` and `/foo` are different routes. When disabled, `/Foo`and `/foo` are treated the same. | `false` |
| ColorScheme | [`Colors`](https://github.com/gofiber/fiber/blob/master/color.go) | You can define custom color scheme. They'll be used for startup message, route list and some middlewares. | [`DefaultColors`](https://github.com/gofiber/fiber/blob/master/color.go) |
| CompressedFileSuffix | `string` | Adds a suffix to the original file name and tries saving the resulting compressed file under the new file name. | `".fiber.gz"` |
| Concurrency | `int` | Maximum number of concurrent connections. | `256 * 1024` |
| DisableDefaultContentType | `bool` | When set to true, causes the default Content-Type header to be excluded from the Response. | `false` |
| DisableDefaultDate | `bool` | When set to true causes the default date header to be excluded from the response. | `false` |
| DisableHeaderNormalizing | `bool` | By default all header names are normalized: conteNT-tYPE -&gt; Content-Type | `false` |
| DisableKeepalive | `bool` | Disable keep-alive connections, the server will close incoming connections after sending the first response to the client | `false` |
| DisablePreParseMultipartForm | `bool` | Will not pre parse Multipart Form data if set to true. This option is useful for servers that desire to treat multipart form data as a binary blob, or choose when to parse the data. | `false` |
| DisableStartupMessage | `bool` | When set to true, it will not print out debug information | `false` |
| ETag | `bool` | Enable or disable ETag header generation, since both weak and strong etags are generated using the same hashing method \(CRC-32\). Weak ETags are the default when enabled. | `false` |
| EnableIPValidation | `bool` | If set to true, `c.IP()` and `c.IPs()` will validate IP addresses before returning them. Also, `c.IP()` will return only the first valid IP rather than just the raw header value that may be a comma separated string.<br /><br />**WARNING:** There is a small performance cost to doing this validation. Keep disabled if speed is your only concern and your application is behind a trusted proxy that already validates this header. | `false` |
| EnablePrintRoutes | `bool` | EnablePrintRoutes enables print all routes with their method, path, name and handler.. | `false` |
| EnableSplittingOnParsers | `bool` | EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true. <br /> <br /> For example, you can use it to parse multiple values from a query parameter like this: `/api?foo=bar,baz == foo[]=bar&foo[]=baz` | `false` |
| EnableTrustedProxyCheck | `bool` | When set to true, fiber will check whether proxy is trusted, using TrustedProxies list. <br /><br />By default `c.Protocol()` will get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header, `c.IP()` will get value from `ProxyHeader` header, `c.Hostname()` will get value from X-Forwarded-Host header. <br /> If `EnableTrustedProxyCheck` is true, and `RemoteIP` is in the list of `TrustedProxies` `c.Protocol()`, `c.IP()`, and `c.Hostname()` will have the same behaviour when `EnableTrustedProxyCheck` disabled, if `RemoteIP` isn't in the list, `c.Protocol()` will return https in case when tls connection is handled by the app, or http otherwise, `c.IP()` will return RemoteIP() from fasthttp context, `c.Hostname()` will return `fasthttp.Request.URI().Host()` | `false` |
| ErrorHandler | `ErrorHandler` | ErrorHandler is executed when an error is returned from fiber.Handler. Mounted fiber error handlers are retained by the top-level app and applied on prefix associated requests. | `DefaultErrorHandler` |
| GETOnly | `bool` | Rejects all non-GET requests if set to true. This option is useful as anti-DoS protection for servers accepting only GET requests. The request size is limited by ReadBufferSize if GETOnly is set. | `false` |
| IdleTimeout | `time.Duration` | The maximum amount of time to wait for the next request when keep-alive is enabled. If IdleTimeout is zero, the value of ReadTimeout is used. | `nil` |
| Immutable | `bool` | When enabled, all values returned by context methods are immutable. By default, they are valid until you return from the handler; see issue [\#185](https://github.com/gofiber/fiber/issues/185). | `false` |
| JSONDecoder | `utils.JSONUnmarshal` | Allowing for flexibility in using another json library for decoding. | `json.Unmarshal` |
| JSONEncoder | `utils.JSONMarshal` | Allowing for flexibility in using another json library for encoding. | `json.Marshal` |
| Network | `string` | Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)<br /><br />**WARNING:** When prefork is set to true, only "tcp4" and "tcp6" can be chosen. | `NetworkTCP4` |
| PassLocalsToViews | `bool` | PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine. See our **Template Middleware** for supported engines. | `false` |
| Prefork | `bool` | Enables use of the[`SO_REUSEPORT`](https://lwn.net/Articles/542629/)socket option. This will spawn multiple Go processes listening on the same port. learn more about [socket sharding](https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/). **NOTE: if enabled, the application will need to be ran through a shell because prefork mode sets environment variables. If you're using Docker, make sure the app is ran with `CMD ./app` or `CMD ["sh", "-c", "/app"]`. For more info, see** [**this**](https://github.com/gofiber/fiber/issues/1021#issuecomment-730537971) **issue comment.** | `false` |
| ProxyHeader | `string` | This will enable `c.IP()` to return the value of the given header key. By default `c.IP()`will return the Remote IP from the TCP connection, this property can be useful if you are behind a load balancer e.g. _X-Forwarded-\*_. | `""` |
| ReadBufferSize | `int` | per-connection buffer size for requests' reading. This also limits the maximum header size. Increase this buffer if your clients send multi-KB RequestURIs and/or multi-KB headers \(for example, BIG cookies\). | `4096` |
| ReadTimeout | `time.Duration` | The amount of time allowed to read the full request, including the body. The default timeout is unlimited. | `nil` |
| RequestMethods | `[]string` | RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish. | `DefaultMethods` |
| ServerHeader | `string` | Enables the `Server` HTTP header with the given value. | `""` |
| StreamRequestBody | `bool` | StreamRequestBody enables request body streaming, and calls the handler sooner when given body is larger than the current limit. | `false` |
| StrictRouting | `bool` | When enabled, the router treats `/foo` and `/foo/` as different. Otherwise, the router treats `/foo` and `/foo/` as the same. | `false` |
| TrustedProxies | `[]string` | Contains the list of trusted proxy IP's. Look at `EnableTrustedProxyCheck` doc. <br /> <br /> It can take IP or IP range addresses. | `[]string*__*` |
| UnescapePath | `bool` | Converts all encoded characters in the route back before setting the path for the context, so that the routing can also work with URL encoded special characters | `false` |
| Views | `Views` | Views is the interface that wraps the Render function. See our **Template Middleware** for supported engines. | `nil` |
| ViewsLayout | `string` | Views Layout is the global layout for all template render until override on Render function. See our **Template Middleware** for supported engines. | `""` |
| WriteBufferSize | `int` | Per-connection buffer size for responses' writing. | `4096` |
| WriteTimeout | `time.Duration` | The maximum duration before timing out writes of the response. The default timeout is unlimited. | `nil` |
| XMLEncoder | `utils.XMLMarshal` | Allowing for flexibility in using another XML library for encoding. | `xml.Marshal` |
| Property | Type | Description | Default |
|---------------------------------------------------------------------------------------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| <Reference id="appname">AppName</Reference> | `string` | This allows to setup app name for the app | `""` |
| <Reference id="bodylimit">BodyLimit</Reference> | `int` | Sets the maximum allowed size for a request body, if the size exceeds the configured limit, it sends `413 - Request Entity Too Large` response. | `4 * 1024 * 1024` |
| <Reference id="casesensitive">CaseSensitive</Reference> | `bool` | When enabled, `/Foo` and `/foo` are different routes. When disabled, `/Foo`and `/foo` are treated the same. | `false` |
| <Reference id="colorscheme">ColorScheme</Reference> | [`Colors`](https://github.com/gofiber/fiber/blob/master/color.go) | You can define custom color scheme. They'll be used for startup message, route list and some middlewares. | [`DefaultColors`](https://github.com/gofiber/fiber/blob/master/color.go) |
| <Reference id="compressedfilesuffix">CompressedFileSuffix</Reference> | `string` | Adds a suffix to the original file name and tries saving the resulting compressed file under the new file name. | `".fiber.gz"` |
| <Reference id="concurrency">Concurrency</Reference> | `int` | Maximum number of concurrent connections. | `256 * 1024` |
| <Reference id="disabledefaultcontenttype">DisableDefaultContentType</Reference> | `bool` | When set to true, causes the default Content-Type header to be excluded from the Response. | `false` |
| <Reference id="disabledefaultdate">DisableDefaultDate</Reference> | `bool` | When set to true causes the default date header to be excluded from the response. | `false` |
| <Reference id="disableheadernormalizing">DisableHeaderNormalizing</Reference> | `bool` | By default all header names are normalized: conteNT-tYPE -&gt; Content-Type | `false` |
| <Reference id="disablekeepalive">DisableKeepalive</Reference> | `bool` | Disable keep-alive connections, the server will close incoming connections after sending the first response to the client | `false` |
| <Reference id="disablepreparsemultipartform">DisablePreParseMultipartForm</Reference> | `bool` | Will not pre parse Multipart Form data if set to true. This option is useful for servers that desire to treat multipart form data as a binary blob, or choose when to parse the data. | `false` |
| <Reference id="enableipvalidation">EnableIPValidation</Reference> | `bool` | If set to true, `c.IP()` and `c.IPs()` will validate IP addresses before returning them. Also, `c.IP()` will return only the first valid IP rather than just the raw header value that may be a comma separated string.<br /><br />**WARNING:** There is a small performance cost to doing this validation. Keep disabled if speed is your only concern and your application is behind a trusted proxy that already validates this header. | `false` |
| <Reference id="enablesplittingonparsers">EnableSplittingOnParsers</Reference> | `bool` | EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true. <br /> <br /> For example, you can use it to parse multiple values from a query parameter like this: `/api?foo=bar,baz == foo[]=bar&foo[]=baz` | `false` |
| <Reference id="enabletrustedproxycheck">EnableTrustedProxyCheck</Reference> | `bool` | When set to true, fiber will check whether proxy is trusted, using TrustedProxies list. <br /><br />By default `c.Protocol()` will get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header, `c.IP()` will get value from `ProxyHeader` header, `c.Hostname()` will get value from X-Forwarded-Host header. <br /> If `EnableTrustedProxyCheck` is true, and `RemoteIP` is in the list of `TrustedProxies` `c.Protocol()`, `c.IP()`, and `c.Hostname()` will have the same behaviour when `EnableTrustedProxyCheck` disabled, if `RemoteIP` isn't in the list, `c.Protocol()` will return https in case when tls connection is handled by the app, or http otherwise, `c.IP()` will return RemoteIP() from fasthttp context, `c.Hostname()` will return `fasthttp.Request.URI().Host()` | `false` |
| <Reference id="errorhandler">ErrorHandler</Reference> | `ErrorHandler` | ErrorHandler is executed when an error is returned from fiber.Handler. Mounted fiber error handlers are retained by the top-level app and applied on prefix associated requests. | `DefaultErrorHandler` |
| <Reference id="getonly">GETOnly</Reference> | `bool` | Rejects all non-GET requests if set to true. This option is useful as anti-DoS protection for servers accepting only GET requests. The request size is limited by ReadBufferSize if GETOnly is set. | `false` |
| <Reference id="idletimeout">IdleTimeout</Reference> | `time.Duration` | The maximum amount of time to wait for the next request when keep-alive is enabled. If IdleTimeout is zero, the value of ReadTimeout is used. | `nil` |
| <Reference id="immutable">Immutable</Reference> | `bool` | When enabled, all values returned by context methods are immutable. By default, they are valid until you return from the handler; see issue [\#185](https://github.com/gofiber/fiber/issues/185). | `false` |
| <Reference id="jsondecoder">JSONDecoder</Reference> | `utils.JSONUnmarshal` | Allowing for flexibility in using another json library for decoding. | `json.Unmarshal` |
| <Reference id="jsonencoder">JSONEncoder</Reference> | `utils.JSONMarshal` | Allowing for flexibility in using another json library for encoding. | `json.Marshal` |
| <Reference id="passlocalstoviews">PassLocalsToViews</Reference> | `bool` | PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine. See our **Template Middleware** for supported engines. | `false` |
| <Reference id="proxyheader">ProxyHeader</Reference> | `string` | This will enable `c.IP()` to return the value of the given header key. By default `c.IP()`will return the Remote IP from the TCP connection, this property can be useful if you are behind a load balancer e.g. _X-Forwarded-\*_. | `""` |
| <Reference id="readbuffersize">ReadBufferSize</Reference> | `int` | per-connection buffer size for requests' reading. This also limits the maximum header size. Increase this buffer if your clients send multi-KB RequestURIs and/or multi-KB headers \(for example, BIG cookies\). | `4096` |
| <Reference id="readtimeout">ReadTimeout</Reference> | `time.Duration` | The amount of time allowed to read the full request, including the body. The default timeout is unlimited. | `nil` |
| <Reference id="reducememoryusage">ReduceMemoryUsage</Reference> | `bool` | Aggressively reduces memory usage at the cost of higher CPU usage if set to true. | `false` |
| <Reference id="requestmethods">RequestMethods</Reference> | `[]string` | RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish. | `DefaultMethods` |
| <Reference id="serverheader">ServerHeader</Reference> | `string` | Enables the `Server` HTTP header with the given value. | `""` |
| <Reference id="streamrequestbody">StreamRequestBody</Reference> | `bool` | StreamRequestBody enables request body streaming, and calls the handler sooner when given body is larger than the current limit. | `false` |
| <Reference id="strictrouting">StrictRouting</Reference> | `bool` | When enabled, the router treats `/foo` and `/foo/` as different. Otherwise, the router treats `/foo` and `/foo/` as the same. | `false` |
| <Reference id="structvalidator">StructValidator</Reference> | `StructValidator` | If you want to validate header/form/query... automatically when to bind, you can define struct validator. Fiber doesn't have default validator, so it'll skip validator step if you don't use any validator. | `nil` |
| <Reference id="trustedproxies">TrustedProxies</Reference> | `[]string` | Contains the list of trusted proxy IP's. Look at `EnableTrustedProxyCheck` doc. <br /> <br /> It can take IP or IP range addresses. | `nil` |
| <Reference id="unescapepath">UnescapePath</Reference> | `bool` | Converts all encoded characters in the route back before setting the path for the context, so that the routing can also work with URL encoded special characters | `false` |
| <Reference id="views">Views</Reference> | `Views` | Views is the interface that wraps the Render function. See our **Template Middleware** for supported engines. | `nil` |
| <Reference id="viewslayout">ViewsLayout</Reference> | `string` | Views Layout is the global layout for all template render until override on Render function. See our **Template Middleware** for supported engines. | `""` |
| <Reference id="writebuffersize">WriteBufferSize</Reference> | `int` | Per-connection buffer size for responses' writing. | `4096` |
| <Reference id="writetimeout">WriteTimeout</Reference> | `time.Duration` | The maximum duration before timing out writes of the response. The default timeout is unlimited. | `nil` |
| <Reference id="xmlencoder">XMLEncoder</Reference> | `utils.XMLMarshal` | Allowing for flexibility in using another XML library for encoding. | `xml.Marshal` |
## NewError
## Server listening
### Config
You can pass an optional ListenConfig when calling the [`Listen`](#listen) or [`Listener`](#listener) method.
```go title="Example"
// Custom config
app.Listen(":8080", fiber.ListenConfig{
EnablePrefork: true,
DisableStartupMessage: true,
})
```
#### Config fields
| Property | Type | Description | Default |
|-------------------------------------------------------------------------|-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|---------|
| <Reference id="beforeservefunc">BeforeServeFunc</Reference> | `func(app *App) error` | Allows customizing and accessing fiber app before serving the app. | `nil` |
| <Reference id="certclientfile">CertClientFile</Reference> | `string` | Path of the client certificate. If you want to use mTLS, you must enter this field. | `""` |
| <Reference id="certfile">CertFile</Reference> | `string` | Path of the certificate file. If you want to use TLS, you must enter this field. | `""` |
| <Reference id="certkeyfile">CertKeyFile</Reference> | `string` | Path of the certificate's private key. If you want to use TLS, you must enter this field. | `""` |
| <Reference id="disablestartupmessage">DisableStartupMessage</Reference> | `bool` | When set to true, it will not print out the «Fiber» ASCII art and listening address. | `false` |
| <Reference id="enableprefork">EnablePrefork</Reference> | `bool` | When set to true, this will spawn multiple Go processes listening on the same port. | `false` |
| <Reference id="enableprintroutes">EnablePrintRoutes</Reference> | `bool` | If set to true, will print all routes with their method, path, and handler. | `false` |
| <Reference id="gracefulcontext">GracefulContext</Reference> | `context.Context` | Field to shutdown Fiber by given context gracefully. | `nil` |
| <Reference id="listeneraddrfunc">ListenerAddrFunc</Reference> | `func(addr net.Addr)` | Allows accessing and customizing `net.Listener`. | `nil` |
| <Reference id="listenernetwork">ListenerNetwork</Reference> | `string` | Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only). WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chosen. | `tcp4` |
| <Reference id="onshutdownerror">OnShutdownError</Reference> | `func(err error)` | Allows to customize error behavior when gracefully shutting down the server by given signal. Prints error with `log.Fatalf()` | `nil` |
| <Reference id="onshutdownsuccess">OnShutdownSuccess</Reference> | `func()` | Allows to customize success behavior when gracefully shutting down the server by given signal. | `nil` |
| <Reference id="tlsconfigfunc">TLSConfigFunc</Reference> | `func(tlsConfig *tls.Config)` | Allows customizing `tls.Config` as you want. | `nil` |
### Listen
Listen serves HTTP requests from the given address.
```go title="Signature"
func (app *App) Listen(addr string, config ...ListenConfig) error
```
```go title="Examples"
// Listen on port :8080
app.Listen(":8080")
// Listen on port :8080 with Prefork
app.Listen(":8080", fiber.ListenConfig{EnablePrefork: true})
// Custom host
app.Listen("127.0.0.1:8080")
```
#### Prefork
Prefork is a feature that allows you to spawn multiple Go processes listening on the same port. This can be useful for scaling across multiple CPU cores.
```go title="Examples"
app.Listen(":8080", fiber.ListenConfig{EnablePrefork: true})
```
This distributes the incoming connections between the spawned processes and allows more requests to be handled simultaneously.
#### TLS
TLS serves HTTPs requests from the given address using certFile and keyFile paths to as TLS certificate and key file.
```go title="Examples"
app.Listen(":443", fiber.ListenConfig{CertFile: "./cert.pem", CertKeyFile: "./cert.key"})
```
#### TLS with certificate
```go title="Examples"
app.Listen(":443", fiber.ListenConfig{CertClientFile: "./ca-chain-cert.pem"})
```
#### TLS with certFile, keyFile and clientCertFile
```go title="Examples"
app.Listen(":443", fiber.ListenConfig{CertFile: "./cert.pem", CertKeyFile: "./cert.key", CertClientFile: "./ca-chain-cert.pem"})
```
### Listener
You can pass your own [`net.Listener`](https://pkg.go.dev/net/#Listener) using the `Listener` method. This method can be used to enable **TLS/HTTPS** with a custom tls.Config.
```go title="Signature"
func (app *App) Listener(ln net.Listener, config ...ListenConfig) error
```
```go title="Examples"
ln, _ := net.Listen("tcp", ":3000")
cer, _:= tls.LoadX509KeyPair("server.crt", "server.key")
ln = tls.NewListener(ln, &tls.Config{Certificates: []tls.Certificate{cer}})
app.Listener(ln)
```
## Server
Server returns the underlying [fasthttp server](https://godoc.org/github.com/valyala/fasthttp#Server)
```go title="Signature"
func (app *App) Server() *fasthttp.Server
```
```go title="Examples"
func main() {
app := fiber.New()
app.Server().MaxConnsPerIP = 1
// ...
}
```
## Server Shutdown
Shutdown gracefully shuts down the server without interrupting any active connections. Shutdown works by first closing all open listeners and then waits indefinitely for all connections to return to idle before shutting down.
ShutdownWithTimeout will forcefully close any active connections after the timeout expires.
ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded.
```go
func (app *App) Shutdown() error
func (app *App) ShutdownWithTimeout(timeout time.Duration) error
func (app *App) ShutdownWithContext(ctx context.Context) error
```
## Helper functions
### NewError
NewError creates a new HTTPError instance with an optional message.
@ -96,7 +232,7 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## IsChild
### IsChild
IsChild determines if the current process is a result of Prefork.
@ -105,16 +241,20 @@ func IsChild() bool
```
```go title="Example"
// Prefork will spawn child processes
app := fiber.New(fiber.Config{
Prefork: true,
// Config app
app := fiber.New()
app.Get("/", func(c fiber.Ctx) error {
if !fiber.IsChild() {
fmt.Println("I'm the parent process")
} else {
fmt.Println("I'm a child process")
}
return c.SendString("Hello, World!")
})
if !fiber.IsChild() {
fmt.Println("I'm the parent process")
} else {
fmt.Println("I'm a child process")
}
// ...
// With prefork enabled, the parent process will spawn child processes
app.Listen(":8080", fiber.ListenConfig{EnablePrefork: true})
```

View File

@ -1,7 +1,7 @@
---
id: hooks
title: 🎣 Hooks
sidebar_position: 6
sidebar_position: 8
---
import Tabs from '@theme/Tabs';

View File

@ -2,7 +2,7 @@
id: log
title: 📃 Log
description: Fiber's built-in log package
sidebar_position: 6
sidebar_position: 7
---
We can use logs to observe program behavior, diagnose problems, or configure corresponding alarms.

264
docs/api/redirect.md Normal file
View File

@ -0,0 +1,264 @@
---
id: redirect
title: ↪️ Redirect
description: Fiber's built-in redirect package
sidebar_position: 5
toc_max_heading_level: 5
---
Is used to redirect the ctx(request) to a different URL/Route.
## Redirect Methods
### To
Redirects to the URL derived from the specified path, with specified [status](#status), a positive integer that
corresponds to an HTTP status code.
:::info
If **not** specified, status defaults to **302 Found**.
:::
```go title="Signature"
func (r *Redirect) To(location string) error
```
```go title="Example"
app.Get("/coffee", func(c fiber.Ctx) error {
// => HTTP - GET 301 /teapot
return c.Redirect().Status(fiber.StatusMovedPermanently).To("/teapot")
})
app.Get("/teapot", func(c fiber.Ctx) error {
return c.Status(fiber.StatusTeapot).Send("🍵 short and stout 🍵")
})
```
```go title="More examples"
app.Get("/", func(c fiber.Ctx) error {
// => HTTP - GET 302 /foo/bar
return c.Redirect().To("/foo/bar")
// => HTTP - GET 302 ../login
return c.Redirect().To("../login")
// => HTTP - GET 302 http://example.com
return c.Redirect().To("http://example.com")
// => HTTP - GET 301 https://example.com
return c.Redirect().Status(301).To("http://example.com")
})
```
### Route
Redirects to the specific route along with the parameters and queries.
:::info
If you want to send queries and params to route, you must use the [**RedirectConfig**](#redirectconfig) struct.
:::
```go title="Signature"
func (r *Redirect) Route(name string, config ...RedirectConfig) error
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
// /user/fiber
return c.Redirect().Route("user", fiber.RedirectConfig{
Params: fiber.Map{
"name": "fiber",
},
})
})
app.Get("/with-queries", func(c fiber.Ctx) error {
// /user/fiber?data[0][name]=john&data[0][age]=10&test=doe
return c.Route("user", RedirectConfig{
Params: fiber.Map{
"name": "fiber",
},
Queries: map[string]string{
"data[0][name]": "john",
"data[0][age]": "10",
"test": "doe",
},
})
})
app.Get("/user/:name", func(c fiber.Ctx) error {
return c.SendString(c.Params("name"))
}).Name("user")
```
### Back
Redirects back to refer URL. It redirects to fallback URL if refer header doesn't exists, with specified status, a
positive integer that corresponds to an HTTP status code.
:::info
If **not** specified, status defaults to **302 Found**.
:::
```go title="Signature"
func (r *Redirect) Back(fallback string) error
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Home page")
})
app.Get("/test", func(c fiber.Ctx) error {
c.Set("Content-Type", "text/html")
return c.SendString(`<a href="/back">Back</a>`)
})
app.Get("/back", func(c fiber.Ctx) error {
return c.Redirect().Back("/")
})
```
## Controls
:::info
Method are **chainable**.
:::
### Status
Sets the HTTP status code for the redirect.
:::info
Is used in conjunction with [**To**](#to), [**Route**](#route) and [**Back**](#back) methods.
:::
```go title="Signature"
func (r *Redirect) Status(status int) *Redirect
```
```go title="Example"
app.Get("/coffee", func(c fiber.Ctx) error {
// => HTTP - GET 301 /teapot
return c.Redirect().Status(fiber.StatusMovedPermanently).To("/teapot")
})
```
### RedirectConfig
Sets the configuration for the redirect.
:::info
Is used in conjunction with the [**Route**](#route) method.
:::
```go
// RedirectConfig A config to use with Redirect().Route()
type RedirectConfig struct {
Params fiber.Map // Route parameters
Queries map[string]string // Query map
}
```
### Flash Message
Similar to [Laravel](https://laravel.com/docs/11.x/redirects#redirecting-with-flashed-session-data) we can flash a message and retrieve it in the next request.
#### Messages
Get flash messages. Check [With](#with) for more information.
```go title="Signature"
func (r *Redirect) Messages() map[string]string
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
messages := c.Redirect().Messages()
return c.JSON(messages)
})
```
#### Message
Get flash message by key. Check [With](#with) for more information.
```go title="Signature"
func (r *Redirect) Message(key string) *Redirect
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
message := c.Redirect().Message("status")
return c.SendString(message)
})
```
#### OldInputs
Get old input data. Check [WithInput](#withinput) for more information.
```go title="Signature"
func (r *Redirect) OldInputs() map[string]string
```
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
oldInputs := c.Redirect().OldInputs()
return c.JSON(oldInputs)
})
```
#### OldInput
Get old input data by key. Check [WithInput](#withinput) for more information.
```go title="Signature"
func (r *Redirect) OldInput(key string) string
```
```go title="Example"
app.Get("/name", func(c fiber.Ctx) error {
oldInput := c.Redirect().OldInput("name")
return c.SendString(oldInput)
})
```
#### With
You can send flash messages by using `With()`.
```go title="Signature"
func (r *Redirect) With(key, value string) *Redirect
```
```go title="Example"
app.Get("/login", func(c fiber.Ctx) error {
return c.Redirect().With("status", "Logged in successfully").To("/")
})
app.Get("/", func(c fiber.Ctx) error {
// => Logged in successfully
return c.SendString(c.Redirect().Message("status"))
})
```
#### WithInput
You can send input data by using `WithInput()`.
They will be sent as a cookie.
This method can send form, multipart form, query data to redirected route depending on the request content type.
```go title="Signature"
func (r *Redirect) WithInput() *Redirect
```
```go title="Example"
// curl -X POST http://localhost:3000/login -d "name=John"
app.Post("/login", func(c fiber.Ctx) error {
return c.Redirect().WithInput().Route("name")
})
app.Get("/name", func(c fiber.Ctx) error {
// => John
return c.SendString(c.Redirect().OldInput("name"))
}).Name("name")
```

View File

@ -1,8 +1,8 @@
{
"label": "Extra",
"position": 4,
"label": "\uD83E\uDDE9 Extra",
"position": 6,
"link": {
"type": "generated-index",
"description": "Extra contents for Fiber."
}
}
}

View File

@ -62,7 +62,7 @@ A complete example demonstrating the use of Air with Fiber can be found in the [
## How do I set up an error handler?
To override the default error handler, you can override the default when providing a [Config](../api/fiber.md#config) when initiating a new [Fiber instance](../api/fiber.md#new).
To override the default error handler, you can override the default when providing a [Config](../api/fiber.md#errorhandler) when initiating a new [Fiber instance](../api/fiber.md#new).
```go title="Example"
app := fiber.New(fiber.Config{

View File

@ -1,6 +1,6 @@
{
"label": "Guide",
"position": 3,
"label": "\uD83D\uDCD6 Guide",
"position": 5,
"link": {
"type": "generated-index",
"description": "Guides for Fiber."

View File

@ -90,7 +90,7 @@ var DefaultErrorHandler = func(c fiber.Ctx, err error) error {
## Custom Error Handler
A custom error handler can be set using a [Config ](../api/fiber.md#config)when initializing a [Fiber instance](../api/fiber.md#new).
A custom error handler can be set using a [Config](../api/fiber.md#errorhandler) when initializing a [Fiber instance](../api/fiber.md#new).
In most cases, the default error handler should be sufficient. However, a custom error handler can come in handy if you want to capture different types of errors and take action accordingly e.g., send a notification email or log an error to the centralized system. You can also send customized responses to the client e.g., error page or just a JSON response.

View File

@ -30,7 +30,8 @@ func main() {
```
### References
- [Set custom JSON encoder for client](../api/client.md#jsonencoder)
- [Set custom JSON decoder for client](../api/client.md#jsondecoder)
- [Set custom JSON encoder for application](../api/fiber.md#config)
- [Set custom JSON decoder for application](../api/fiber.md#config)
- [Set custom JSON encoder for application](../api/fiber.md#jsonencoder)
- [Set custom JSON decoder for application](../api/fiber.md#jsondecoder)

View File

@ -5,6 +5,7 @@ description: >-
Routing refers to how an application's endpoints (URIs) respond to client
requests.
sidebar_position: 1
toc_max_heading_level: 4
---
import Tabs from '@theme/Tabs';
@ -150,21 +151,21 @@ Constraints aren't validation for parameters. If constraints aren't valid for a
| Constraint | Example | Example matches |
| ----------------- | ------------------------------------ | ------------------------------------------------------------------------------------------- |
| int | :id<int\> | 123456789, -123456789 |
| bool | :active<bool\> | true,false |
| guid | :id<guid\> | CD2C1638-1638-72D5-1638-DEADBEEF1638 |
| float | :weight<float\> | 1.234, -1,001.01e8 |
| minLen(value) | :username<minLen(4)\> | Test (must be at least 4 characters) |
| maxLen(value) | :filename<maxLen(8)\> | MyFile (must be no more than 8 characters |
| len(length) | :filename<len(12)\> | somefile.txt (exactly 12 characters) |
| min(value) | :age<min(18)\> | 19 (Integer value must be at least 18) |
| max(value) | :age<max(120)\> | 91 (Integer value must be no more than 120) |
| range(min,max) | :age<range(18,120)\> | 91 (Integer value must be at least 18 but no more than 120) |
| alpha | :name<alpha\> | Rick (String must consist of one or more alphabetical characters, a-z and case-insensitive) |
| datetime | :dob<datetime(2006\\\\-01\\\\-02)\> | 2005-11-01 |
| regex(expression) | :date<regex(\\d{4}-\\d{2}-\\d{2})\> | 2022-08-27 (Must match regular expression) |
| int | `:id<int\>` | 123456789, -123456789 |
| bool | `:active<bool\>` | true,false |
| guid | `:id<guid\>` | CD2C1638-1638-72D5-1638-DEADBEEF1638 |
| float | `:weight<float\>` | 1.234, -1,001.01e8 |
| minLen(value) | `:username<minLen(4)\>` | Test (must be at least 4 characters) |
| maxLen(value) | `:filename<maxLen(8)\>` | MyFile (must be no more than 8 characters |
| len(length) | `:filename<len(12)\>` | somefile.txt (exactly 12 characters) |
| min(value) | `:age<min(18)\>` | 19 (Integer value must be at least 18) |
| max(value) | `:age<max(120)\>` | 91 (Integer value must be no more than 120) |
| range(min,max) | `:age<range(18,120)\>` | 91 (Integer value must be at least 18 but no more than 120) |
| alpha | `:name<alpha\>` | Rick (String must consist of one or more alphabetical characters, a-z and case-insensitive) |
| datetime | `:dob<datetime(2006\\\\-01\\\\-02)\>` | 2005-11-01 |
| regex(expression) | `:date<regex(\\d{4}-\\d{2}-\\d{2})\>` | 2022-08-27 (Must match regular expression) |
**Examples**
#### Examples
<Tabs>
<TabItem value="single-constraint" label="Single Constraint">
@ -224,7 +225,7 @@ app.Get(`/:date<regex(\d{4}-\d{2}-\d{2})>`, func(c fiber.Ctx) error {
You should use `\\` before routing-specific characters when to use datetime constraint (`*`, `+`, `?`, `:`, `/`, `<`, `>`, `;`, `(`, `)`), to avoid wrong parsing.
:::
**Optional Parameter Example**
#### Optional Parameter Example
You can impose constraints on optional parameters as well.
@ -240,7 +241,7 @@ app.Get("/:test<int>?", func(c fiber.Ctx) error {
// Cannot GET /7.0
```
**Custom Constraint Example**
#### Custom Constraint
Custom constraints can be added to Fiber using the `app.RegisterCustomConstraint` method. Your constraints have to be compatible with the `CustomConstraint` interface.
@ -297,7 +298,7 @@ func main() {
Functions that are designed to make changes to the request or response are called **middleware functions**. The [Next](../api/ctx.md#next) is a **Fiber** router function, when called, executes the **next** function that **matches** the current route.
**Example of a middleware function**
### Example of a middleware function
```go
app.Use(func(c fiber.Ctx) error {

125
docs/guide/utils.md Normal file
View File

@ -0,0 +1,125 @@
---
id: utils
title: 🧰 Utils
sidebar_position: 8
toc_max_heading_level: 4
---
## Generics
### Convert
Converts a string value to a specified type, handling errors and optional default values.
This function simplifies the conversion process by encapsulating error handling and the management of default values, making your code cleaner and more consistent.
```go title="Signature"
func Convert[T any](value string, convertor func(string) (T, error), defaultValue ...T) (*T, error)
```
```go title="Example"
// GET http://example.com/id/bb70ab33-d455-4a03-8d78-d3c1dacae9ff
app.Get("/id/:id", func(c fiber.Ctx) error {
fiber.Convert(c.Params("id"), uuid.Parse) // UUID(bb70ab33-d455-4a03-8d78-d3c1dacae9ff), nil
// GET http://example.com/search?id=65f6f54221fb90e6a6b76db7
app.Get("/search", func(c fiber.Ctx) error) {
fiber.Convert(c.Query("id"), mongo.ParseObjectID) // objectid(65f6f54221fb90e6a6b76db7), nil
fiber.Convert(c.Query("id"), uuid.Parse) // uuid.Nil, error(cannot parse given uuid)
fiber.Convert(c.Query("id"), uuid.Parse, mongo.NewObjectID) // new object id generated and return nil as error.
}
// ...
})
```
### GetReqHeader
GetReqHeader function utilizing Go's generics feature.
This function allows for retrieving HTTP request headers with a more specific data type.
```go title="Signature"
func GetReqHeader[V any](c Ctx, key string, defaultValue ...V) V
```
```go title="Example"
app.Get("/search", func(c fiber.Ctx) error {
// curl -X GET http://example.com/search -H "X-Request-ID: 12345" -H "X-Request-Name: John"
GetReqHeader[int](c, "X-Request-ID") // => returns 12345 as integer.
GetReqHeader[string](c, "X-Request-Name") // => returns "John" as string.
GetReqHeader[string](c, "unknownParam", "default") // => returns "default" as string.
// ...
})
```
### Locals
Locals function utilizing Go's generics feature.
This function allows for manipulating and retrieving local values within a request context with a more specific data type.
```go title="Signature"
func Locals[V any](c Ctx, key any, value ...V) V
// get local value
func Locals[V any](c Ctx, key any) V
// set local value
func Locals[V any](c Ctx, key any, value ...V) V
```
```go title="Example"
app.Use("/user/:user/:id", func(c fiber.Ctx) error {
// set local values
fiber.Locals[string](c, "user", "john")
fiber.Locals[int](c, "id", 25)
// ...
return c.Next()
})
app.Get("/user/*", func(c fiber.Ctx) error {
// get local values
name := fiber.Locals[string](c, "user") // john
age := fiber.Locals[int](c, "id") // 25
// ...
})
```
### Params
Params function utilizing Go's generics feature.
This function allows for retrieving route parameters with a more specific data type.
```go title="Signature"
func Params[V any](c Ctx, key string, defaultValue ...V) V
```
```go title="Example"
app.Get("/user/:user/:id", func(c fiber.Ctx) error {
// http://example.com/user/john/25
Params[int](c, "id") // => returns 25 as integer.
Params[int](c, "unknownParam", 99) // => returns the default 99 as integer.
// ...
return c.SendString("Hello, " + fiber.Params[string](c, "user"))
})
```
### Query
Query function utilizing Go's generics feature.
This function allows for retrieving query parameters with a more specific data type.
```go title="Signature"
func Query[V any](c Ctx, key string, defaultValue ...V) V
```
```go title="Example"
app.Get("/search", func(c fiber.Ctx) error {
// http://example.com/search?name=john&age=25
Query[string](c, "name") // => returns "john"
Query[int](c, "age") // => returns 25 as integer.
Query[string](c, "unknownParam", "default") // => returns "default" as string.
// ...
})
```

View File

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

View File

@ -92,7 +92,7 @@ func main() {
}
```
```text
```bash
go run server.go
```

View File

@ -1,9 +1,9 @@
{
"label": "🧬 Middleware",
"position": 7,
"label": "\uD83E\uDDEC Middleware",
"position": 4,
"collapsed": true,
"link": {
"type": "generated-index",
"description": "Middleware is a function chained in the HTTP request cycle with access to the Context which it uses to perform a specific action, for example, logging every request or enabling CORS."
}
}
}

View File

@ -66,7 +66,7 @@ app.Get("/", func(c fiber.Ctx) error {
| Property | Type | Description | Default |
|:---------------------|:------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------|
| Next | `func(fiber.Ctx) bool` | Next defines a function that is executed before creating the cache entry and can be used to execute the request without cache creation. If an entry already exists, it will be used. If you want to completely bypass the cache functionality in certain cases, you should use the [skip middleware](./skip.md). | `nil` |
| Next | `func(fiber.Ctx) bool` | Next defines a function that is executed before creating the cache entry and can be used to execute the request without cache creation. If an entry already exists, it will be used. If you want to completely bypass the cache functionality in certain cases, you should use the [skip middleware](skip.md). | `nil` |
| Expiration | `time.Duration` | Expiration is the time that a cached response will live. | `1 * time.Minute` |
| CacheHeader | `string` | CacheHeader is the header on the response header that indicates the cache status, with the possible return values "hit," "miss," or "unreachable." | `X-Cache` |
| CacheControl | `bool` | CacheControl enables client-side caching if set to true. | `false` |

View File

@ -6,7 +6,7 @@ id: csrf
The CSRF middleware for [Fiber](https://github.com/gofiber/fiber) provides protection against [Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks. Requests made using methods other than those defined as 'safe' by [RFC9110#section-9.2.1](https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.2.1) (GET, HEAD, OPTIONS, and TRACE) are validated using tokens. If a potential attack is detected, the middleware will return a default 403 Forbidden error.
This middleware offers two [Token Validation Patterns](#token-validation-patterns): the [Double Submit Cookie Pattern (default)](#double-submit-cookie-pattern-default), and the [Synchronizer Token Pattern (with Session)](#synchronizer-token-pattern-session).
This middleware offers two [Token Validation Patterns](#token-validation-patterns): the [Double Submit Cookie Pattern (default)](#double-submit-cookie-pattern-default), and the [Synchronizer Token Pattern (with Session)](#synchronizer-token-pattern-with-session).
As a [Defense In Depth](#defense-in-depth) measure, this middleware performs [Referer Checking](#referer-checking) for HTTPS requests.
@ -180,7 +180,7 @@ app.Use(csrf.New(csrf.Config{
}))
```
::caution
:::caution
When using `TrustedOrigins` with subdomain matching, make sure you control and trust all the subdomains, including all subdomain levels. If not, an attacker could create a subdomain under a trusted origin and use it to send harmful requests.
:::

View File

@ -3,26 +3,28 @@ id: route-handlers
title: Route Handlers
---
import Reference from '@site/src/components/reference';
Registers a route bound to a specific [HTTP method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods).
```go title="Signatures"
// HTTP methods
func (app *App) Get(path string, handlers ...Handler) Router
func (app *App) Head(path string, handlers ...Handler) Router
func (app *App) Post(path string, handlers ...Handler) Router
func (app *App) Put(path string, handlers ...Handler) Router
func (app *App) Delete(path string, handlers ...Handler) Router
func (app *App) Connect(path string, handlers ...Handler) Router
func (app *App) Options(path string, handlers ...Handler) Router
func (app *App) Trace(path string, handlers ...Handler) Router
func (app *App) Patch(path string, handlers ...Handler) Router
func (app *App) Get(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Head(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Post(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Put(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Delete(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Connect(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Options(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Trace(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Patch(path string, handler Handler, middlewares ...Handler) Router
// Add allows you to specify a method as value
func (app *App) Add(method, path string, handlers ...Handler) Router
func (app *App) Add(method, path string, handler Handler, middlewares ...Handler) Router
// All will register the route on all HTTP methods
// Almost the same as app.Use but not bound to prefixes
func (app *App) All(path string, handlers ...Handler) Router
func (app *App) All(path string, handler Handler, middlewares ...Handler) Router
```
```go title="Examples"
@ -37,10 +39,18 @@ app.Post("/api/register", func(c fiber.Ctx) error {
})
```
**Use** can be used for middleware packages and prefix catchers. These routes will only match the beginning of each path i.e. `/john` will match `/john/doe`, `/johnnnnn` etc
<Reference id="use">**Use**</Reference>
Can be used for middleware packages and prefix catchers. These routes will only match the beginning of each path i.e. `/john` will match `/john/doe`, `/johnnnnn` etc
```go title="Signature"
func (app *App) Use(args ...any) Router
// Different usage variations
func (app *App) Use(handler Handler, middlewares ...Handler) Router
func (app *App) Use(path string, handler Handler, middlewares ...Handler) Router
func (app *App) Use(paths []string, handler Handler, middlewares ...Handler) Router
func (app *App) Use(path string, app *App) Router
```
```go title="Examples"
@ -66,4 +76,7 @@ app.Use("/api", func(c fiber.Ctx) error {
}, func(c fiber.Ctx) error {
return c.Next()
})
// Mount a sub-app
app.Use("/api", api)
```

111
docs/whats_new.md Normal file
View File

@ -0,0 +1,111 @@
---
id: whats_new
title: 🆕 Whats New in v3
sidebar_position: 2
---
:::caution
Its a draft, not finished yet.
:::
[//]: # (https://github.com/gofiber/fiber/releases/tag/v3.0.0-beta.2)
## 🎉 Welcome to Fiber v3
We are excited to announce the release of Fiber v3! 🚀
Fiber v3 is a major release with a lot of new features, improvements, and breaking changes. We have worked hard to make Fiber even faster, more flexible, and easier to use.
## 🚀 Highlights
### Drop for old Go versions
Fiber v3 drops support for Go versions below 1.21. We recommend upgrading to Go 1.21 or higher to use Fiber v3.
### App changes
We have made several changes to the Fiber app, including:
* Listen -> unified with config
* app.Config properties moved to listen config
* DisableStartupMessage
* EnablePrefork -> previously Prefork
* EnablePrintRoutes
* ListenerNetwork -> previously Network
#### new methods
* RegisterCustomBinder
* RegisterCustomConstraint
* NewCtxFunc
#### removed methods
* Mount -> Use app.Use() instead
* ListenTLS -> Use app.Listen() with tls.Config
* ListenTLSWithCertificate -> Use app.Listen() with tls.Config
* ListenMutualTLS -> Use app.Listen() with tls.Config
* ListenMutualTLSWithCertificate -> Use app.Listen() with tls.Config
#### changed methods
* Routing methods -> Get(), Post(), Put(), Delete(), Patch(), Options(), Trace(), Connect() and All()
* Use -> can be used for app mounting
* Test -> timeout changed to 1 second
* Listen -> has a config parameter
* Listener -> has a config parameter
### Context change
#### interface
#### customizable
#### new methods
* AutoFormat -> ExpressJs like
* Host -> ExpressJs like
* Port -> ExpressJs like
* IsProxyTrusted
* Reset
* Schema -> ExpressJs like
* SendStream -> ExpressJs like
* SendString -> ExpressJs like
* String -> ExpressJs like
* ViewBind -> instead of Bind
#### removed methods
* AllParams -> c.Bind().URL() ?
* ParamsInt -> Params Generic
* QueryBool -> Query Generic
* QueryFloat -> Query Generic
* QueryInt -> Query Generic
* BodyParser -> c.Bind().Body()
* CookieParser -> c.Bind().Cookie()
* ParamsParser -> c.Bind().URL()
* RedirectToRoute -> c.Redirect().Route()
* RedirectBack -> c.Redirect().Back()
* ReqHeaderParser -> c.Bind().Header()
#### changed methods
* Bind -> for Binding instead of View, us c.ViewBind()
* Format -> Param: body interface{} -> handlers ...ResFmt
* Redirect -> c.Redirect().To()
### Client package
### Binding
### Generic functions
### Middleware refactoring
#### Session middleware
#### Filesystem middleware
### Monitor middleware
Monitor middleware is now in Contrib package.
## Migration guide
...

View File

@ -14,6 +14,7 @@ import (
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
"sync"
"time"
@ -697,336 +698,6 @@ func IsMethodIdempotent(m string) bool {
}
}
// HTTP methods were copied from net/http.
const (
MethodGet = "GET" // RFC 7231, 4.3.1
MethodHead = "HEAD" // RFC 7231, 4.3.2
MethodPost = "POST" // RFC 7231, 4.3.3
MethodPut = "PUT" // RFC 7231, 4.3.4
MethodPatch = "PATCH" // RFC 5789
MethodDelete = "DELETE" // RFC 7231, 4.3.5
MethodConnect = "CONNECT" // RFC 7231, 4.3.6
MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
MethodTrace = "TRACE" // RFC 7231, 4.3.8
methodUse = "USE"
)
// MIME types that are commonly used
const (
MIMETextXML = "text/xml"
MIMETextHTML = "text/html"
MIMETextPlain = "text/plain"
MIMETextJavaScript = "text/javascript"
MIMEApplicationXML = "application/xml"
MIMEApplicationJSON = "application/json"
// Deprecated: use MIMETextJavaScript instead
MIMEApplicationJavaScript = "application/javascript"
MIMEApplicationForm = "application/x-www-form-urlencoded"
MIMEOctetStream = "application/octet-stream"
MIMEMultipartForm = "multipart/form-data"
MIMETextXMLCharsetUTF8 = "text/xml; charset=utf-8"
MIMETextHTMLCharsetUTF8 = "text/html; charset=utf-8"
MIMETextPlainCharsetUTF8 = "text/plain; charset=utf-8"
MIMETextJavaScriptCharsetUTF8 = "text/javascript; charset=utf-8"
MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=utf-8"
MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
// Deprecated: use MIMETextJavaScriptCharsetUTF8 instead
MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8"
)
// HTTP status codes were copied from net/http with the following updates:
// - Rename StatusNonAuthoritativeInfo to StatusNonAuthoritativeInformation
// - Add StatusSwitchProxy (306)
// NOTE: Keep this list in sync with statusMessage
const (
StatusContinue = 100 // RFC 9110, 15.2.1
StatusSwitchingProtocols = 101 // RFC 9110, 15.2.2
StatusProcessing = 102 // RFC 2518, 10.1
StatusEarlyHints = 103 // RFC 8297
StatusOK = 200 // RFC 9110, 15.3.1
StatusCreated = 201 // RFC 9110, 15.3.2
StatusAccepted = 202 // RFC 9110, 15.3.3
StatusNonAuthoritativeInformation = 203 // RFC 9110, 15.3.4
StatusNoContent = 204 // RFC 9110, 15.3.5
StatusResetContent = 205 // RFC 9110, 15.3.6
StatusPartialContent = 206 // RFC 9110, 15.3.7
StatusMultiStatus = 207 // RFC 4918, 11.1
StatusAlreadyReported = 208 // RFC 5842, 7.1
StatusIMUsed = 226 // RFC 3229, 10.4.1
StatusMultipleChoices = 300 // RFC 9110, 15.4.1
StatusMovedPermanently = 301 // RFC 9110, 15.4.2
StatusFound = 302 // RFC 9110, 15.4.3
StatusSeeOther = 303 // RFC 9110, 15.4.4
StatusNotModified = 304 // RFC 9110, 15.4.5
StatusUseProxy = 305 // RFC 9110, 15.4.6
StatusSwitchProxy = 306 // RFC 9110, 15.4.7 (Unused)
StatusTemporaryRedirect = 307 // RFC 9110, 15.4.8
StatusPermanentRedirect = 308 // RFC 9110, 15.4.9
StatusBadRequest = 400 // RFC 9110, 15.5.1
StatusUnauthorized = 401 // RFC 9110, 15.5.2
StatusPaymentRequired = 402 // RFC 9110, 15.5.3
StatusForbidden = 403 // RFC 9110, 15.5.4
StatusNotFound = 404 // RFC 9110, 15.5.5
StatusMethodNotAllowed = 405 // RFC 9110, 15.5.6
StatusNotAcceptable = 406 // RFC 9110, 15.5.7
StatusProxyAuthRequired = 407 // RFC 9110, 15.5.8
StatusRequestTimeout = 408 // RFC 9110, 15.5.9
StatusConflict = 409 // RFC 9110, 15.5.10
StatusGone = 410 // RFC 9110, 15.5.11
StatusLengthRequired = 411 // RFC 9110, 15.5.12
StatusPreconditionFailed = 412 // RFC 9110, 15.5.13
StatusRequestEntityTooLarge = 413 // RFC 9110, 15.5.14
StatusRequestURITooLong = 414 // RFC 9110, 15.5.15
StatusUnsupportedMediaType = 415 // RFC 9110, 15.5.16
StatusRequestedRangeNotSatisfiable = 416 // RFC 9110, 15.5.17
StatusExpectationFailed = 417 // RFC 9110, 15.5.18
StatusTeapot = 418 // RFC 9110, 15.5.19 (Unused)
StatusMisdirectedRequest = 421 // RFC 9110, 15.5.20
StatusUnprocessableEntity = 422 // RFC 9110, 15.5.21
StatusLocked = 423 // RFC 4918, 11.3
StatusFailedDependency = 424 // RFC 4918, 11.4
StatusTooEarly = 425 // RFC 8470, 5.2.
StatusUpgradeRequired = 426 // RFC 9110, 15.5.22
StatusPreconditionRequired = 428 // RFC 6585, 3
StatusTooManyRequests = 429 // RFC 6585, 4
StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5
StatusUnavailableForLegalReasons = 451 // RFC 7725, 3
StatusInternalServerError = 500 // RFC 9110, 15.6.1
StatusNotImplemented = 501 // RFC 9110, 15.6.2
StatusBadGateway = 502 // RFC 9110, 15.6.3
StatusServiceUnavailable = 503 // RFC 9110, 15.6.4
StatusGatewayTimeout = 504 // RFC 9110, 15.6.5
StatusHTTPVersionNotSupported = 505 // RFC 9110, 15.6.6
StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1
StatusInsufficientStorage = 507 // RFC 4918, 11.5
StatusLoopDetected = 508 // RFC 5842, 7.2
StatusNotExtended = 510 // RFC 2774, 7
StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)
// Errors
var (
ErrBadRequest = NewError(StatusBadRequest) // 400
ErrUnauthorized = NewError(StatusUnauthorized) // 401
ErrPaymentRequired = NewError(StatusPaymentRequired) // 402
ErrForbidden = NewError(StatusForbidden) // 403
ErrNotFound = NewError(StatusNotFound) // 404
ErrMethodNotAllowed = NewError(StatusMethodNotAllowed) // 405
ErrNotAcceptable = NewError(StatusNotAcceptable) // 406
ErrProxyAuthRequired = NewError(StatusProxyAuthRequired) // 407
ErrRequestTimeout = NewError(StatusRequestTimeout) // 408
ErrConflict = NewError(StatusConflict) // 409
ErrGone = NewError(StatusGone) // 410
ErrLengthRequired = NewError(StatusLengthRequired) // 411
ErrPreconditionFailed = NewError(StatusPreconditionFailed) // 412
ErrRequestEntityTooLarge = NewError(StatusRequestEntityTooLarge) // 413
ErrRequestURITooLong = NewError(StatusRequestURITooLong) // 414
ErrUnsupportedMediaType = NewError(StatusUnsupportedMediaType) // 415
ErrRequestedRangeNotSatisfiable = NewError(StatusRequestedRangeNotSatisfiable) // 416
ErrExpectationFailed = NewError(StatusExpectationFailed) // 417
ErrTeapot = NewError(StatusTeapot) // 418
ErrMisdirectedRequest = NewError(StatusMisdirectedRequest) // 421
ErrUnprocessableEntity = NewError(StatusUnprocessableEntity) // 422
ErrLocked = NewError(StatusLocked) // 423
ErrFailedDependency = NewError(StatusFailedDependency) // 424
ErrTooEarly = NewError(StatusTooEarly) // 425
ErrUpgradeRequired = NewError(StatusUpgradeRequired) // 426
ErrPreconditionRequired = NewError(StatusPreconditionRequired) // 428
ErrTooManyRequests = NewError(StatusTooManyRequests) // 429
ErrRequestHeaderFieldsTooLarge = NewError(StatusRequestHeaderFieldsTooLarge) // 431
ErrUnavailableForLegalReasons = NewError(StatusUnavailableForLegalReasons) // 451
ErrInternalServerError = NewError(StatusInternalServerError) // 500
ErrNotImplemented = NewError(StatusNotImplemented) // 501
ErrBadGateway = NewError(StatusBadGateway) // 502
ErrServiceUnavailable = NewError(StatusServiceUnavailable) // 503
ErrGatewayTimeout = NewError(StatusGatewayTimeout) // 504
ErrHTTPVersionNotSupported = NewError(StatusHTTPVersionNotSupported) // 505
ErrVariantAlsoNegotiates = NewError(StatusVariantAlsoNegotiates) // 506
ErrInsufficientStorage = NewError(StatusInsufficientStorage) // 507
ErrLoopDetected = NewError(StatusLoopDetected) // 508
ErrNotExtended = NewError(StatusNotExtended) // 510
ErrNetworkAuthenticationRequired = NewError(StatusNetworkAuthenticationRequired) // 511
)
// HTTP Headers were copied from net/http.
const (
HeaderAuthorization = "Authorization"
HeaderProxyAuthenticate = "Proxy-Authenticate"
HeaderProxyAuthorization = "Proxy-Authorization"
HeaderWWWAuthenticate = "WWW-Authenticate"
HeaderAge = "Age"
HeaderCacheControl = "Cache-Control"
HeaderClearSiteData = "Clear-Site-Data"
HeaderExpires = "Expires"
HeaderPragma = "Pragma"
HeaderWarning = "Warning"
HeaderAcceptCH = "Accept-CH"
HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
HeaderContentDPR = "Content-DPR"
HeaderDPR = "DPR"
HeaderEarlyData = "Early-Data"
HeaderSaveData = "Save-Data"
HeaderViewportWidth = "Viewport-Width"
HeaderWidth = "Width"
HeaderETag = "ETag"
HeaderIfMatch = "If-Match"
HeaderIfModifiedSince = "If-Modified-Since"
HeaderIfNoneMatch = "If-None-Match"
HeaderIfUnmodifiedSince = "If-Unmodified-Since"
HeaderLastModified = "Last-Modified"
HeaderVary = "Vary"
HeaderConnection = "Connection"
HeaderKeepAlive = "Keep-Alive"
HeaderAccept = "Accept"
HeaderAcceptCharset = "Accept-Charset"
HeaderAcceptEncoding = "Accept-Encoding"
HeaderAcceptLanguage = "Accept-Language"
HeaderCookie = "Cookie"
HeaderExpect = "Expect"
HeaderMaxForwards = "Max-Forwards"
HeaderSetCookie = "Set-Cookie"
HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
HeaderAccessControlMaxAge = "Access-Control-Max-Age"
HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
HeaderOrigin = "Origin"
HeaderTimingAllowOrigin = "Timing-Allow-Origin"
HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
HeaderDNT = "DNT"
HeaderTk = "Tk"
HeaderContentDisposition = "Content-Disposition"
HeaderContentEncoding = "Content-Encoding"
HeaderContentLanguage = "Content-Language"
HeaderContentLength = "Content-Length"
HeaderContentLocation = "Content-Location"
HeaderContentType = "Content-Type"
HeaderForwarded = "Forwarded"
HeaderVia = "Via"
HeaderXForwardedFor = "X-Forwarded-For"
HeaderXForwardedHost = "X-Forwarded-Host"
HeaderXForwardedProto = "X-Forwarded-Proto"
HeaderXForwardedProtocol = "X-Forwarded-Protocol"
HeaderXForwardedSsl = "X-Forwarded-Ssl"
HeaderXUrlScheme = "X-Url-Scheme"
HeaderLocation = "Location"
HeaderFrom = "From"
HeaderHost = "Host"
HeaderReferer = "Referer"
HeaderReferrerPolicy = "Referrer-Policy"
HeaderUserAgent = "User-Agent"
HeaderAllow = "Allow"
HeaderServer = "Server"
HeaderAcceptRanges = "Accept-Ranges"
HeaderContentRange = "Content-Range"
HeaderIfRange = "If-Range"
HeaderRange = "Range"
HeaderContentSecurityPolicy = "Content-Security-Policy"
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy"
HeaderExpectCT = "Expect-CT"
HeaderPermissionsPolicy = "Permissions-Policy"
HeaderPublicKeyPins = "Public-Key-Pins"
HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only"
HeaderStrictTransportSecurity = "Strict-Transport-Security"
HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests"
HeaderXContentTypeOptions = "X-Content-Type-Options"
HeaderXDownloadOptions = "X-Download-Options"
HeaderXFrameOptions = "X-Frame-Options"
HeaderXPoweredBy = "X-Powered-By"
HeaderXXSSProtection = "X-XSS-Protection"
HeaderLastEventID = "Last-Event-ID"
HeaderNEL = "NEL"
HeaderPingFrom = "Ping-From"
HeaderPingTo = "Ping-To"
HeaderReportTo = "Report-To"
HeaderTE = "TE"
HeaderTrailer = "Trailer"
HeaderTransferEncoding = "Transfer-Encoding"
HeaderSecWebSocketAccept = "Sec-WebSocket-Accept"
HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions"
HeaderSecWebSocketKey = "Sec-WebSocket-Key"
HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol"
HeaderSecWebSocketVersion = "Sec-WebSocket-Version"
HeaderAcceptPatch = "Accept-Patch"
HeaderAcceptPushPolicy = "Accept-Push-Policy"
HeaderAcceptSignature = "Accept-Signature"
HeaderAltSvc = "Alt-Svc"
HeaderDate = "Date"
HeaderIndex = "Index"
HeaderLargeAllocation = "Large-Allocation"
HeaderLink = "Link"
HeaderPushPolicy = "Push-Policy"
HeaderRetryAfter = "Retry-After"
HeaderServerTiming = "Server-Timing"
HeaderSignature = "Signature"
HeaderSignedHeaders = "Signed-Headers"
HeaderSourceMap = "SourceMap"
HeaderUpgrade = "Upgrade"
HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
HeaderXPingback = "X-Pingback"
HeaderXRequestID = "X-Request-ID"
HeaderXRequestedWith = "X-Requested-With"
HeaderXRobotsTag = "X-Robots-Tag"
HeaderXUACompatible = "X-UA-Compatible"
HeaderAccessControlAllowPrivateNetwork = "Access-Control-Allow-Private-Network"
HeaderAccessControlRequestPrivateNetwork = "Access-Control-Request-Private-Network"
)
// Network types that are commonly used
const (
NetworkTCP = "tcp"
NetworkTCP4 = "tcp4"
NetworkTCP6 = "tcp6"
)
// Compression types
const (
StrGzip = "gzip"
StrBr = "br"
StrDeflate = "deflate"
StrBrotli = "brotli"
)
// Cookie SameSite
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
const (
CookieSameSiteDisabled = "disabled" // not in RFC, just control "SameSite" attribute will not be set.
CookieSameSiteLaxMode = "lax"
CookieSameSiteStrictMode = "strict"
CookieSameSiteNoneMode = "none"
)
// Route Constraints
const (
ConstraintInt = "int"
ConstraintBool = "bool"
ConstraintFloat = "float"
ConstraintAlpha = "alpha"
ConstraintGUID = "guid"
ConstraintMinLen = "minLen"
ConstraintMaxLen = "maxLen"
ConstraintLen = "len"
ConstraintBetweenLen = "betweenLen"
ConstraintMinLenLower = "minlen"
ConstraintMaxLenLower = "maxlen"
ConstraintBetweenLenLower = "betweenlen"
ConstraintMin = "min"
ConstraintMax = "max"
ConstraintRange = "range"
ConstraintDatetime = "datetime"
ConstraintRegex = "regex"
)
func IndexRune(str string, needle int32) bool {
for _, b := range str {
if b == needle {
@ -1035,3 +706,109 @@ func IndexRune(str string, needle int32) bool {
}
return false
}
// assertValueType asserts the type of the result to the type of the value
func assertValueType[V GenericType, T any](result T) V {
v, ok := any(result).(V)
if !ok {
panic(fmt.Errorf("failed to type-assert to %T", v))
}
return v
}
func genericParseDefault[V GenericType](err error, parser func() V, defaultValue ...V) V {
var v V
if err != nil {
if len(defaultValue) > 0 {
return defaultValue[0]
}
return v
}
return parser()
}
func genericParseInt[V GenericType](str string, bitSize int, parser func(int64) V, defaultValue ...V) V {
result, err := strconv.ParseInt(str, 10, bitSize)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseUint[V GenericType](str string, bitSize int, parser func(uint64) V, defaultValue ...V) V {
result, err := strconv.ParseUint(str, 10, bitSize)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseFloat[V GenericType](str string, bitSize int, parser func(float64) V, defaultValue ...V) V {
result, err := strconv.ParseFloat(str, bitSize)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseBool[V GenericType](str string, parser func(bool) V, defaultValue ...V) V {
result, err := strconv.ParseBool(str)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseType[V GenericType](str string, v V, defaultValue ...V) V {
switch any(v).(type) {
case int:
return genericParseInt[V](str, 0, func(i int64) V { return assertValueType[V, int](int(i)) }, defaultValue...)
case int8:
return genericParseInt[V](str, 8, func(i int64) V { return assertValueType[V, int8](int8(i)) }, defaultValue...)
case int16:
return genericParseInt[V](str, 16, func(i int64) V { return assertValueType[V, int16](int16(i)) }, defaultValue...)
case int32:
return genericParseInt[V](str, 32, func(i int64) V { return assertValueType[V, int32](int32(i)) }, defaultValue...)
case int64:
return genericParseInt[V](str, 64, func(i int64) V { return assertValueType[V, int64](i) }, defaultValue...)
case uint:
return genericParseUint[V](str, 32, func(i uint64) V { return assertValueType[V, uint](uint(i)) }, defaultValue...)
case uint8:
return genericParseUint[V](str, 8, func(i uint64) V { return assertValueType[V, uint8](uint8(i)) }, defaultValue...)
case uint16:
return genericParseUint[V](str, 16, func(i uint64) V { return assertValueType[V, uint16](uint16(i)) }, defaultValue...)
case uint32:
return genericParseUint[V](str, 32, func(i uint64) V { return assertValueType[V, uint32](uint32(i)) }, defaultValue...)
case uint64:
return genericParseUint[V](str, 64, func(i uint64) V { return assertValueType[V, uint64](i) }, defaultValue...)
case float32:
return genericParseFloat[V](str, 32, func(i float64) V { return assertValueType[V, float32](float32(i)) }, defaultValue...)
case float64:
return genericParseFloat[V](str, 64, func(i float64) V { return assertValueType[V, float64](i) }, defaultValue...)
case bool:
return genericParseBool[V](str, func(b bool) V { return assertValueType[V, bool](b) }, defaultValue...)
case string:
if str == "" && len(defaultValue) > 0 {
return defaultValue[0]
}
return assertValueType[V, string](str)
case []byte:
if str == "" && len(defaultValue) > 0 {
return defaultValue[0]
}
return assertValueType[V, []byte]([]byte(str))
default:
if len(defaultValue) > 0 {
return defaultValue[0]
}
return v
}
}
type GenericType interface {
GenericTypeInteger | GenericTypeFloat | bool | string | []byte
}
type GenericTypeInteger interface {
GenericTypeIntegerSigned | GenericTypeIntegerUnsigned
}
type GenericTypeIntegerSigned interface {
int | int8 | int16 | int32 | int64
}
type GenericTypeIntegerUnsigned interface {
uint | uint8 | uint16 | uint32 | uint64
}
type GenericTypeFloat interface {
float32 | float64
}

View File

@ -101,7 +101,8 @@ type ListenConfig struct {
// OnShutdownError allows to customize error behavior when to graceful shutdown server by given signal.
//
// Default: Print error with log.Fatalf()
// Print error with log.Fatalf() by default.
// Default: nil
OnShutdownError func(err error)
// OnShutdownSuccess allows to customize success behavior when to graceful shutdown server by given signal.

View File

@ -32,7 +32,7 @@ const (
CookieDataAssigner = ":"
)
// Redirect is a struct to use it with Ctx.
// Redirect is a struct that holds the redirect data.
type Redirect struct {
c *DefaultCtx // Embed ctx
status int // Status code of redirection. Default: StatusFound
@ -41,7 +41,7 @@ type Redirect struct {
oldInput map[string]string // Old input data
}
// A config to use with Redirect().Route()
// RedirectConfig A config to use with Redirect().Route()
// You can specify queries or route parameters.
// NOTE: We don't use net/url to parse parameters because of it has poor performance. You have to pass map.
type RedirectConfig struct {
@ -86,7 +86,7 @@ func (r *Redirect) Status(code int) *Redirect {
return r
}
// You can send flash messages by using With().
// With You can send flash messages by using With().
// They will be sent as a cookie.
// You can get them by using: Redirect().Messages(), Redirect().Message()
// Note: You must use escape char before using ',' and ':' chars to avoid wrong parsing.
@ -96,7 +96,7 @@ func (r *Redirect) With(key, value string) *Redirect {
return r
}
// You can send input data by using WithInput().
// WithInput You can send input data by using WithInput().
// They will be sent as a cookie.
// This method can send form, multipart form, query data to redirected route.
// You can get them by using: Redirect().OldInputs(), Redirect().OldInput()
@ -117,7 +117,7 @@ func (r *Redirect) WithInput() *Redirect {
return r
}
// Get flash messages.
// Messages Get flash messages.
func (r *Redirect) Messages() map[string]string {
msgs := r.c.redirectionMessages
flashMessages := make(map[string]string, len(msgs))
@ -133,7 +133,7 @@ func (r *Redirect) Messages() map[string]string {
return flashMessages
}
// Get flash message by key.
// Message Get flash message by key.
func (r *Redirect) Message(key string) string {
msgs := r.c.redirectionMessages
@ -147,7 +147,7 @@ func (r *Redirect) Message(key string) string {
return ""
}
// Get old input data.
// OldInputs Get old input data.
func (r *Redirect) OldInputs() map[string]string {
msgs := r.c.redirectionMessages
oldInputs := make(map[string]string, len(msgs))
@ -163,7 +163,7 @@ func (r *Redirect) OldInputs() map[string]string {
return oldInputs
}
// Get old input data by key.
// OldInput Get old input data by key.
func (r *Redirect) OldInput(key string) string {
msgs := r.c.redirectionMessages
@ -177,7 +177,7 @@ func (r *Redirect) OldInput(key string) string {
return ""
}
// Redirect to the URL derived from the specified path, with specified status.
// To redirect to the URL derived from the specified path, with specified status.
func (r *Redirect) To(location string) error {
r.c.setCanonical(HeaderLocation, location)
r.c.Status(r.status)
@ -253,7 +253,7 @@ func (r *Redirect) Route(name string, config ...RedirectConfig) error {
return r.To(location)
}
// Redirect back to the URL to referer.
// Back redirect to the URL to referer.
func (r *Redirect) Back(fallback ...string) error {
location := r.c.Get(HeaderReferer)
if location == "" {
@ -289,6 +289,7 @@ func (r *Redirect) setFlash() {
r.c.ClearCookie(FlashCookieName)
}
// parseMessage is a helper function to parse flash messages and old input data
func parseMessage(raw string) (string, string) { //nolint: revive // not necessary
if i := findNextNonEscapedCharsetPosition(raw, []byte(CookieDataAssigner)); i != -1 {
return RemoveEscapeChar(raw[:i]), RemoveEscapeChar(raw[i+1:])

112
utils.go
View File

@ -1,112 +0,0 @@
package fiber
import (
"fmt"
"strconv"
)
// assertValueType asserts the type of the result to the type of the value
func assertValueType[V GenericType, T any](result T) V {
v, ok := any(result).(V)
if !ok {
panic(fmt.Errorf("failed to type-assert to %T", v))
}
return v
}
func genericParseDefault[V GenericType](err error, parser func() V, defaultValue ...V) V {
var v V
if err != nil {
if len(defaultValue) > 0 {
return defaultValue[0]
}
return v
}
return parser()
}
func genericParseInt[V GenericType](str string, bitSize int, parser func(int64) V, defaultValue ...V) V {
result, err := strconv.ParseInt(str, 10, bitSize)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseUint[V GenericType](str string, bitSize int, parser func(uint64) V, defaultValue ...V) V {
result, err := strconv.ParseUint(str, 10, bitSize)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseFloat[V GenericType](str string, bitSize int, parser func(float64) V, defaultValue ...V) V {
result, err := strconv.ParseFloat(str, bitSize)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseBool[V GenericType](str string, parser func(bool) V, defaultValue ...V) V {
result, err := strconv.ParseBool(str)
return genericParseDefault[V](err, func() V { return parser(result) }, defaultValue...)
}
func genericParseType[V GenericType](str string, v V, defaultValue ...V) V {
switch any(v).(type) {
case int:
return genericParseInt[V](str, 0, func(i int64) V { return assertValueType[V, int](int(i)) }, defaultValue...)
case int8:
return genericParseInt[V](str, 8, func(i int64) V { return assertValueType[V, int8](int8(i)) }, defaultValue...)
case int16:
return genericParseInt[V](str, 16, func(i int64) V { return assertValueType[V, int16](int16(i)) }, defaultValue...)
case int32:
return genericParseInt[V](str, 32, func(i int64) V { return assertValueType[V, int32](int32(i)) }, defaultValue...)
case int64:
return genericParseInt[V](str, 64, func(i int64) V { return assertValueType[V, int64](i) }, defaultValue...)
case uint:
return genericParseUint[V](str, 32, func(i uint64) V { return assertValueType[V, uint](uint(i)) }, defaultValue...)
case uint8:
return genericParseUint[V](str, 8, func(i uint64) V { return assertValueType[V, uint8](uint8(i)) }, defaultValue...)
case uint16:
return genericParseUint[V](str, 16, func(i uint64) V { return assertValueType[V, uint16](uint16(i)) }, defaultValue...)
case uint32:
return genericParseUint[V](str, 32, func(i uint64) V { return assertValueType[V, uint32](uint32(i)) }, defaultValue...)
case uint64:
return genericParseUint[V](str, 64, func(i uint64) V { return assertValueType[V, uint64](i) }, defaultValue...)
case float32:
return genericParseFloat[V](str, 32, func(i float64) V { return assertValueType[V, float32](float32(i)) }, defaultValue...)
case float64:
return genericParseFloat[V](str, 64, func(i float64) V { return assertValueType[V, float64](i) }, defaultValue...)
case bool:
return genericParseBool[V](str, func(b bool) V { return assertValueType[V, bool](b) }, defaultValue...)
case string:
if str == "" && len(defaultValue) > 0 {
return defaultValue[0]
}
return assertValueType[V, string](str)
case []byte:
if str == "" && len(defaultValue) > 0 {
return defaultValue[0]
}
return assertValueType[V, []byte]([]byte(str))
default:
if len(defaultValue) > 0 {
return defaultValue[0]
}
return v
}
}
type GenericType interface {
GenericTypeInteger | GenericTypeFloat | bool | string | []byte
}
type GenericTypeInteger interface {
GenericTypeIntegerSigned | GenericTypeIntegerUnsigned
}
type GenericTypeIntegerSigned interface {
int | int8 | int16 | int32 | int64
}
type GenericTypeIntegerUnsigned interface {
uint | uint8 | uint16 | uint32 | uint64
}
type GenericTypeFloat interface {
float32 | float64
}