Skip to content

Commit aac1b97

Browse files
committed
Implement Fluent Method Chaining for Status and Type Methods Using Generics #3221
1 parent 8970f51 commit aac1b97

20 files changed

+650
-535
lines changed

app.go

+86-57
Large diffs are not rendered by default.

bind.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
type CustomBinder interface {
1010
Name() string
1111
MIMETypes() []string
12-
Parse(c Ctx, out any) error
12+
Parse(c Ctx[any], out any) error
1313
}
1414

1515
// StructValidator is an interface to register custom struct validator for binding.
@@ -19,7 +19,7 @@ type StructValidator interface {
1919

2020
// Bind struct
2121
type Bind struct {
22-
ctx Ctx
22+
ctx Ctx[any]
2323
dontHandleErrs bool
2424
}
2525

ctx.go

+11-10
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ const userContextKey contextKey = 0 // __local_user_context__
4747
// generation tool `go install github.com/vburenin/ifacemaker@975a95966976eeb2d4365a7fb236e274c54da64c`
4848
// https://github.com/vburenin/ifacemaker/blob/975a95966976eeb2d4365a7fb236e274c54da64c/ifacemaker.go#L14-L30
4949
//
50-
//go:generate ifacemaker --file ctx.go --struct DefaultCtx --iface Ctx --pkg fiber --output ctx_interface_gen.go --not-exported true --iface-comment "Ctx represents the Context which hold the HTTP request and response.\nIt has methods for the request query string, parameters, body, HTTP headers and so on."
50+
//go:generate ifacemaker --file ctx.go --struct DefaultCtx --iface Ctx --pkg fiber --output ctx_interface.go --not-exported true --iface-comment "Ctx represents the Context which hold the HTTP request and response.\nIt has methods for the request query string, parameters, body, HTTP headers and so on."
51+
//go:generate go run ctx_interface_gen.go
5152
type DefaultCtx struct {
52-
app *App // Reference to *App
53+
app *App[Ctx[any]] // Reference to *App
5354
route *Route // Reference to *Route
5455
fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx
5556
bind *Bind // Default bind reference
@@ -197,7 +198,7 @@ type Views interface {
197198

198199
// ResFmt associates a Content Type to a fiber.Handler for c.Format
199200
type ResFmt struct {
200-
Handler func(Ctx) error
201+
Handler func(Ctx[any]) error
201202
MediaType string
202203
}
203204

@@ -222,7 +223,7 @@ func (c *DefaultCtx) AcceptsLanguages(offers ...string) string {
222223
}
223224

224225
// App returns the *App reference to the instance of the Fiber application
225-
func (c *DefaultCtx) App() *App {
226+
func (c *DefaultCtx) App() *App[DefaultCtx] {
226227
return c.app
227228
}
228229

@@ -642,7 +643,7 @@ func (c *DefaultCtx) Get(key string, defaultValue ...string) string {
642643

643644
// GetReqHeader returns the HTTP request header specified by filed.
644645
// This function is generic and can handle different headers type values.
645-
func GetReqHeader[V GenericType](c Ctx, key string, defaultValue ...V) V {
646+
func GetReqHeader[V GenericType](c Ctx[any], key string, defaultValue ...V) V {
646647
var v V
647648
return genericParseType[V](c.App().getString(c.Request().Header.Peek(key)), v, defaultValue...)
648649
}
@@ -978,7 +979,7 @@ func (c *DefaultCtx) Locals(key any, value ...any) any {
978979
// All the values are removed from ctx after returning from the top
979980
// RequestHandler. Additionally, Close method is called on each value
980981
// implementing io.Closer before removing the value from ctx.
981-
func Locals[V any](c Ctx, key any, value ...V) V {
982+
func Locals[V any](c Ctx[any], key any, value ...V) V {
982983
var v V
983984
var ok bool
984985
if len(value) == 0 {
@@ -1114,7 +1115,7 @@ func (c *DefaultCtx) Params(key string, defaultValue ...string) string {
11141115
//
11151116
// http://example.com/id/:number -> http://example.com/id/john
11161117
// Params[int](c, "number", 0) -> returns 0 because can't parse 'john' as integer.
1117-
func Params[V GenericType](c Ctx, key string, defaultValue ...V) V {
1118+
func Params[V GenericType](c Ctx[any], key string, defaultValue ...V) V {
11181119
var v V
11191120
return genericParseType(c.Params(key), v, defaultValue...)
11201121
}
@@ -1236,7 +1237,7 @@ func (c *DefaultCtx) Queries() map[string]string {
12361237
// name := Query[string](c, "search") // Returns "john"
12371238
// age := Query[int](c, "age") // Returns 8
12381239
// unknown := Query[string](c, "unknown", "default") // Returns "default" since the query parameter "unknown" is not found
1239-
func Query[V GenericType](c Ctx, key string, defaultValue ...V) V {
1240+
func Query[V GenericType](c Ctx[any], key string, defaultValue ...V) V {
12401241
var v V
12411242
q := c.App().getString(c.RequestCtx().QueryArgs().Peek(key))
12421243

@@ -1730,7 +1731,7 @@ func (c *DefaultCtx) Stale() bool {
17301731

17311732
// Status sets the HTTP status for the response.
17321733
// This method is chainable.
1733-
func (c *DefaultCtx) Status(status int) Ctx {
1734+
func (c *DefaultCtx) Status(status int) Ctx[DefaultCtx] {
17341735
c.fasthttp.Response.SetStatusCode(status)
17351736
return c
17361737
}
@@ -1775,7 +1776,7 @@ func (c *DefaultCtx) String() string {
17751776
}
17761777

17771778
// Type sets the Content-Type HTTP header to the MIME type specified by the file extension.
1778-
func (c *DefaultCtx) Type(extension string, charset ...string) Ctx {
1779+
func (c *DefaultCtx) Type(extension string, charset ...string) Ctx[DefaultCtx] {
17791780
if len(charset) > 0 {
17801781
c.fasthttp.Response.Header.SetContentType(utils.GetMIME(extension) + "; charset=" + charset[0])
17811782
} else {

ctx_custom_interface.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
2+
// 🤖 Github Repository: https://github.com/gofiber/fiber
3+
// 📌 API Documentation: https://docs.gofiber.io
4+
5+
package fiber
6+
7+
import (
8+
"errors"
9+
10+
"github.com/valyala/fasthttp"
11+
)
12+
13+
type CustomCtx[T any] interface {
14+
Ctx[T]
15+
16+
// Reset is a method to reset context fields by given request when to use server handlers.
17+
Reset(fctx *fasthttp.RequestCtx)
18+
19+
// Methods to use with next stack.
20+
getMethodINT() int
21+
getIndexRoute() int
22+
getTreePath() string
23+
getDetectionPath() string
24+
getPathOriginal() string
25+
getValues() *[maxParams]string
26+
getMatched() bool
27+
setIndexHandler(handler int)
28+
setIndexRoute(route int)
29+
setMatched(matched bool)
30+
setRoute(route *Route)
31+
}
32+
33+
func NewDefaultCtx(app *App[DefaultCtx]) *DefaultCtx {
34+
// return ctx
35+
return &DefaultCtx{
36+
// Set app reference
37+
app: app,
38+
}
39+
}
40+
41+
func (app *App[TCtx]) newCtx() Ctx[TCtx] {
42+
var c Ctx[TCtx]
43+
44+
if app.newCtxFunc != nil {
45+
c = app.newCtxFunc(app)
46+
} else {
47+
c = NewDefaultCtx(app)
48+
}
49+
50+
return c
51+
}
52+
53+
// AcquireCtx retrieves a new Ctx from the pool.
54+
func (app *App[TCtx]) AcquireCtx(fctx *fasthttp.RequestCtx) Ctx[TCtx] {
55+
ctx, ok := app.pool.Get().(Ctx)
56+
57+
if !ok {
58+
panic(errors.New("failed to type-assert to Ctx"))
59+
}
60+
ctx.Reset(fctx)
61+
62+
return ctx
63+
}
64+
65+
// ReleaseCtx releases the ctx back into the pool.
66+
func (app *App[TCtx]) ReleaseCtx(c Ctx[TCtx]) {
67+
c.release()
68+
app.pool.Put(c)
69+
}

0 commit comments

Comments
 (0)