Skip to content

Commit 9df17c3

Browse files
authored
Merge pull request #4436 from neko-sc/feat/http-query-method
🔥 feat: Add HTTP QUERY method support (RFC 10008)
2 parents 6f77383 + fc3d025 commit 9df17c3

20 files changed

Lines changed: 293 additions & 9 deletions

File tree

app.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ const (
599599
methodOptions
600600
methodTrace
601601
methodPatch
602+
methodQuery
602603
)
603604

604605
// HTTP methods enabled by default
@@ -612,6 +613,7 @@ var DefaultMethods = []string{
612613
methodOptions: MethodOptions,
613614
methodTrace: MethodTrace,
614615
methodPatch: MethodPatch,
616+
methodQuery: MethodQuery,
615617
}
616618

617619
// httpReadResponse - Used for test mocking http.ReadResponse
@@ -1082,6 +1084,12 @@ func (app *App) Patch(path string, handler any, handlers ...any) Router {
10821084
return app.Add([]string{MethodPatch}, path, handler, handlers...)
10831085
}
10841086

1087+
// Query registers a route for QUERY methods that performs a safe, idempotent
1088+
// query with a request body.
1089+
func (app *App) Query(path string, handler any, handlers ...any) Router {
1090+
return app.Add([]string{MethodQuery}, path, handler, handlers...)
1091+
}
1092+
10851093
// Add allows you to specify multiple HTTP methods to register a route.
10861094
// The provided handlers are executed in order, starting with `handler` and then the variadic `handlers`.
10871095
func (app *App) Add(methods []string, path string, handler any, handlers ...any) Router {

app_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,9 @@ func Test_App_Methods(t *testing.T) {
12981298
app.Trace("/:john?/:doe?", dummyHandler)
12991299
testStatus200(t, app, "/john/doe", MethodTrace)
13001300

1301+
app.Query("/:john?/:doe?", dummyHandler)
1302+
testStatus200(t, app, "/john/doe", MethodQuery)
1303+
13011304
app.Get("/:john?/:doe?", dummyHandler)
13021305
testStatus200(t, app, "/john/doe", MethodGet)
13031306

@@ -1767,6 +1770,9 @@ func Test_App_Group(t *testing.T) {
17671770
grp.Trace("/TRACE", dummyHandler)
17681771
testStatus200(t, app, "/test/TRACE", MethodTrace)
17691772

1773+
grp.Query("/QUERY", dummyHandler)
1774+
testStatus200(t, app, "/test/QUERY", MethodQuery)
1775+
17701776
grp.All("/ALL", dummyHandler)
17711777
testStatus200(t, app, "/test/ALL", MethodPost)
17721778

@@ -1804,7 +1810,8 @@ func Test_App_RouteChain(t *testing.T) {
18041810
Connect(dummyHandler).
18051811
Options(dummyHandler).
18061812
Trace(dummyHandler).
1807-
Patch(dummyHandler)
1813+
Patch(dummyHandler).
1814+
Query(dummyHandler)
18081815

18091816
testStatus200(t, app, "/test", MethodGet)
18101817
testStatus200(t, app, "/test", MethodHead)
@@ -1815,6 +1822,7 @@ func Test_App_RouteChain(t *testing.T) {
18151822
testStatus200(t, app, "/test", MethodOptions)
18161823
testStatus200(t, app, "/test", MethodTrace)
18171824
testStatus200(t, app, "/test", MethodPatch)
1825+
testStatus200(t, app, "/test", MethodQuery)
18181826

18191827
register.RouteChain("/v1").Get(dummyHandler).Post(dummyHandler)
18201828

@@ -2603,6 +2611,7 @@ func Test_App_Stack(t *testing.T) {
26032611
app.Get("/path1", testEmptyHandler)
26042612
app.Get("/path2", testEmptyHandler)
26052613
app.Post("/path3", testEmptyHandler)
2614+
app.Query("/path4", testEmptyHandler)
26062615

26072616
app.startupProcess()
26082617

@@ -2618,6 +2627,7 @@ func Test_App_Stack(t *testing.T) {
26182627
require.Len(t, stack[app.methodInt(MethodConnect)], 1)
26192628
require.Len(t, stack[app.methodInt(MethodOptions)], 1)
26202629
require.Len(t, stack[app.methodInt(MethodTrace)], 1)
2630+
require.Len(t, stack[app.methodInt(MethodQuery)], 2)
26212631
}
26222632

26232633
// go test -run Test_App_HandlersCount

client/request.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,11 @@ func (r *Request) Patch(url string) (*Response, error) {
664664
return r.SetURL(url).SetMethod(fiber.MethodPatch).Send()
665665
}
666666

667+
// Query sends a QUERY request to the given URL.
668+
func (r *Request) Query(url string) (*Response, error) {
669+
return r.SetURL(url).SetMethod(fiber.MethodQuery).Send()
670+
}
671+
667672
// Custom sends a request with a custom HTTP method to the given URL.
668673
func (r *Request) Custom(url, method string) (*Response, error) {
669674
return r.SetURL(url).SetMethod(method).Send()

client/request_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,34 @@ func Test_Request_Patch(t *testing.T) {
10671067
}
10681068
}
10691069

1070+
func Test_Request_Query(t *testing.T) {
1071+
t.Parallel()
1072+
1073+
app, ln, start := createHelperServer(t)
1074+
1075+
app.Query("/", func(c fiber.Ctx) error {
1076+
return c.Send(c.Body())
1077+
})
1078+
1079+
go start()
1080+
time.Sleep(100 * time.Millisecond)
1081+
1082+
client := New().SetDial(ln)
1083+
1084+
for range 5 {
1085+
resp, err := AcquireRequest().
1086+
SetClient(client).
1087+
SetRawBody([]byte("query body")).
1088+
Query("http://example.com")
1089+
1090+
require.NoError(t, err)
1091+
require.Equal(t, fiber.StatusOK, resp.StatusCode())
1092+
require.Equal(t, "query body", resp.String())
1093+
1094+
resp.Close()
1095+
}
1096+
}
1097+
10701098
func Test_Request_Header_With_Server(t *testing.T) {
10711099
t.Parallel()
10721100
handler := func(c fiber.Ctx) error {

constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const (
1111
MethodConnect = "CONNECT" // RFC 7231, 4.3.6
1212
MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
1313
MethodTrace = "TRACE" // RFC 7231, 4.3.8
14+
MethodQuery = "QUERY" // RFC 10008
1415
methodUse = "USE"
1516
)
1617

docs/api/constants.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
MethodConnect = "CONNECT" // RFC 7231, 4.3.6
1919
MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
2020
MethodTrace = "TRACE" // RFC 7231, 4.3.8
21+
MethodQuery = "QUERY" // RFC 10008
2122
methodUse = "USE"
2223
)
2324
```

docs/client/request.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ func (r *Request) Head(url string) (*Response, error)
101101
func (r *Request) Options(url string) (*Response, error)
102102
```
103103

104+
### Query
105+
106+
**Query** sends a QUERY request. It sets the URL and method to QUERY, then sends the request.
107+
108+
```go title="Signature"
109+
func (r *Request) Query(url string) (*Response, error)
110+
```
111+
104112
### Custom
105113

106114
**Custom** sends a request using a custom HTTP method. For example, you can use this to send a TRACE or CONNECT request.

docs/partials/routing/handler.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func (app *App) Connect(path string, handler any, handlers ...any) Router
1616
func (app *App) Options(path string, handler any, handlers ...any) Router
1717
func (app *App) Trace(path string, handler any, handlers ...any) Router
1818
func (app *App) Patch(path string, handler any, handlers ...any) Router
19+
func (app *App) Query(path string, handler any, handlers ...any) Router
1920

2021
// Add registers the same handlers on multiple methods at once.
2122
// The handlers run in order, starting with `handler` and then the variadic `handlers`.

domain.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,12 @@ func (d *domainRouter) Patch(path string, handler any, handlers ...any) Router {
527527
return d.Add([]string{MethodPatch}, path, handler, handlers...)
528528
}
529529

530+
// Query registers a route for QUERY methods.
531+
// The handler only executes when the request hostname matches the domain pattern.
532+
func (d *domainRouter) Query(path string, handler any, handlers ...any) Router {
533+
return d.Add([]string{MethodQuery}, path, handler, handlers...)
534+
}
535+
530536
// Add allows you to specify multiple HTTP methods to register a route.
531537
// The handler only executes when the request hostname matches the domain pattern.
532538
func (d *domainRouter) Add(methods []string, path string, handler any, handlers ...any) Router {
@@ -674,6 +680,10 @@ func (r *domainRegistering) Patch(handler any, handlers ...any) Register {
674680
return r.Add([]string{MethodPatch}, handler, handlers...)
675681
}
676682

683+
func (r *domainRegistering) Query(handler any, handlers ...any) Register {
684+
return r.Add([]string{MethodQuery}, handler, handlers...)
685+
}
686+
677687
func (r *domainRegistering) Add(methods []string, handler any, handlers ...any) Register {
678688
converted := collectHandlers("domain", append([]any{handler}, handlers...)...)
679689
wrapped := r.domain.wrapHandlers(converted)

domain_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ func Test_Domain_HTTPMethods(t *testing.T) {
255255
{method: MethodPut, reg: func(r Router, p string, h any, hs ...any) Router { return r.Put(p, h, hs...) }},
256256
{method: MethodDelete, reg: func(r Router, p string, h any, hs ...any) Router { return r.Delete(p, h, hs...) }},
257257
{method: MethodPatch, reg: func(r Router, p string, h any, hs ...any) Router { return r.Patch(p, h, hs...) }},
258+
{method: MethodQuery, reg: func(r Router, p string, h any, hs ...any) Router { return r.Query(p, h, hs...) }},
258259
{method: MethodOptions, reg: func(r Router, p string, h any, hs ...any) Router { return r.Options(p, h, hs...) }},
259260
{method: MethodConnect, reg: func(r Router, p string, h any, hs ...any) Router { return r.Connect(p, h, hs...) }},
260261
{method: MethodTrace, reg: func(r Router, p string, h any, hs ...any) Router { return r.Trace(p, h, hs...) }},
@@ -1058,8 +1059,11 @@ func Test_Domain_RouteChainAllMethods(t *testing.T) {
10581059
rc.Patch(func(c Ctx) error {
10591060
return c.SendString("patch")
10601061
})
1062+
rc.Query(func(c Ctx) error {
1063+
return c.SendString("query")
1064+
})
10611065

1062-
for _, method := range []string{MethodPut, MethodDelete, MethodPatch, MethodOptions} {
1066+
for _, method := range []string{MethodPut, MethodDelete, MethodPatch, MethodOptions, MethodQuery} {
10631067
req := httptest.NewRequest(method, "/test", http.NoBody)
10641068
req.Host = "api.example.com"
10651069
resp, err := app.Test(req)

0 commit comments

Comments
 (0)