Skip to content

Commit 4af1b9e

Browse files
committed
Refactor init and add compression support.
- Break to `/v2` to introduce `Options{}` that's pass to lib init. - Add `CompressOptions{}` to enable zstd|br|gzip|deflate auto-compression support offered by fasthttp.
1 parent 9a0624f commit 4af1b9e

File tree

16 files changed

+187
-49
lines changed

16 files changed

+187
-49
lines changed

.github/workflows/go-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
test:
88
strategy:
99
matrix:
10-
go: ["1.21", "1.20", "1.18", "1.19"]
10+
go: ["1.21"]
1111

1212
runs-on: ubuntu-20.04
1313

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ write HTTP servers. It enables:
2323
## Install
2424

2525
```bash
26-
go get -u github.com/zerodha/fastglue
26+
go get -u github.com/zerodha/fastglue/v2
2727
```
2828

2929
## Usage
3030

3131
```go
32-
import "github.com/zerodha/fastglue"
32+
import "github.com/zerodha/fastglue/v2"
3333
```
3434

3535
## Examples

custom.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ type Envelope struct {
3131

3232
// NewGlue creates and returns a new instance of Fastglue with custom error
3333
// handlers pre-bound.
34-
func NewGlue() *Fastglue {
35-
f := New()
34+
func NewGlue(o Options) *Fastglue {
35+
f := New(o)
3636
f.Router.MethodNotAllowed = BadMethodHandler
3737
f.Router.NotFound = NotFoundHandler
3838
f.Router.SaveMatchedRoutePath = true

examples/before-after/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"time"
99

1010
"github.com/valyala/fasthttp"
11-
"github.com/zerodha/fastglue"
11+
"github.com/zerodha/fastglue/v2"
1212
)
1313

1414
var (
@@ -18,7 +18,7 @@ var (
1818
func main() {
1919
flag.Parse()
2020

21-
g := fastglue.New()
21+
g := fastglue.New(fastglue.Options{})
2222
g.Before(setTime)
2323
g.After(calculateTime)
2424
g.GET("/", handleIndex)

examples/decode/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"time"
88

99
"github.com/valyala/fasthttp"
10-
"github.com/zerodha/fastglue"
10+
"github.com/zerodha/fastglue/v2"
1111
)
1212

1313
var (
@@ -17,7 +17,7 @@ var (
1717
func main() {
1818
flag.Parse()
1919

20-
g := fastglue.New()
20+
g := fastglue.New(fastglue.Options{})
2121
g.GET("/", handleIndex)
2222

2323
s := &fasthttp.Server{

examples/example.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"time"
66

77
"github.com/valyala/fasthttp"
8-
"github.com/zerodha/fastglue"
8+
"github.com/zerodha/fastglue/v2"
99
)
1010

1111
// App is the global config "context" that'll be injected into every Request.
@@ -77,7 +77,7 @@ func myRedirectHandler(r *fastglue.Request) error {
7777
}
7878

7979
func main() {
80-
f := fastglue.NewGlue()
80+
f := fastglue.NewGlue(fastglue.Options{})
8181
f.SetContext(&App{version: "v3.0.0"})
8282
// f.Before(checkToken)
8383

examples/graceful/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"time"
1010

1111
"github.com/valyala/fasthttp"
12-
"github.com/zerodha/fastglue"
12+
"github.com/zerodha/fastglue/v2"
1313
)
1414

1515
var (
@@ -19,7 +19,7 @@ var (
1919
func main() {
2020
flag.Parse()
2121

22-
g := fastglue.New()
22+
g := fastglue.New(fastglue.Options{})
2323
g.ServeStatic("/{filepath:*}", ".", true)
2424

2525
s := &fasthttp.Server{

examples/helloworld/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"time"
88

99
"github.com/valyala/fasthttp"
10-
"github.com/zerodha/fastglue"
10+
"github.com/zerodha/fastglue/v2"
1111
)
1212

1313
var (
@@ -17,7 +17,7 @@ var (
1717
func main() {
1818
flag.Parse()
1919

20-
g := fastglue.New()
20+
g := fastglue.New(fastglue.Options{})
2121
g.GET("/", handleHelloWorld)
2222

2323
s := &fasthttp.Server{

examples/middleware/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"time"
1010

1111
"github.com/valyala/fasthttp"
12-
"github.com/zerodha/fastglue"
12+
"github.com/zerodha/fastglue/v2"
1313
)
1414

1515
var (
@@ -19,7 +19,7 @@ var (
1919
func main() {
2020
flag.Parse()
2121

22-
g := fastglue.New()
22+
g := fastglue.New(fastglue.Options{})
2323
g.GET("/", auth(validateAll(handleGetAll)))
2424
g.PUT("/", auth(fastglue.ReqLenParams(validate(handleMiddleware), map[string]int{"a": 5, "b": 5})))
2525
g.POST("/", auth(fastglue.ReqParams(validate(handleMiddleware), []string{"a", "b"})))

examples/path/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"time"
99

1010
"github.com/valyala/fasthttp"
11-
"github.com/zerodha/fastglue"
11+
"github.com/zerodha/fastglue/v2"
1212
)
1313

1414
var (
@@ -18,7 +18,7 @@ var (
1818
func main() {
1919
flag.Parse()
2020

21-
g := fastglue.New()
21+
g := fastglue.New(fastglue.Options{})
2222
g.GET("/", handleIndex)
2323
g.GET("/{name:^[a-zA-Z]+$}", handleIndex)
2424

examples/singleton/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"time"
99

1010
"github.com/valyala/fasthttp"
11-
"github.com/zerodha/fastglue"
11+
"github.com/zerodha/fastglue/v2"
1212
)
1313

1414
var (
@@ -29,7 +29,7 @@ func main() {
2929
log: log.New(os.Stdout, "SINGLETON", log.Llongfile),
3030
}
3131

32-
g := fastglue.New()
32+
g := fastglue.New(fastglue.Options{})
3333
g.SetContext(app)
3434
g.GET("/", handleIndex)
3535

examples/static-file/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"time"
77

88
"github.com/valyala/fasthttp"
9-
"github.com/zerodha/fastglue"
9+
"github.com/zerodha/fastglue/v2"
1010
)
1111

1212
var (
@@ -16,7 +16,7 @@ var (
1616
func main() {
1717
flag.Parse()
1818

19-
g := fastglue.New()
19+
g := fastglue.New(fastglue.Options{})
2020
g.ServeStatic("/{filepath:*}", ".", true)
2121

2222
s := &fasthttp.Server{

fastglue.go

+76-6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ var (
3838
authToken = []byte("token")
3939
)
4040

41+
// CompressionType is the type of otuput compression available in fasthttp
42+
// for the response body.
43+
type CompressionType string
44+
45+
const (
46+
CompressionZstd CompressionType = "zstd"
47+
CompressionBr CompressionType = "br"
48+
CompressionGzip CompressionType = "gzip"
49+
CompressionDeflate CompressionType = "deflate"
50+
)
51+
4152
// FastRequestHandler is the fastglue HTTP request handler function
4253
// that wraps over the fasthttp handler.
4354
type FastRequestHandler func(*Request) error
@@ -53,21 +64,52 @@ type Request struct {
5364
Context interface{}
5465
}
5566

67+
// CompressionOpt is the configuration for enabling and controlling compression.
68+
// Enabling this will automatically compress the response based on the client's
69+
// Accept-Encoding header by internally invoking fasthttp.CompressHandler()
70+
// gzip|deflate|br|zstd are the supported compression types.
71+
type CompressionOpt struct {
72+
Enabled bool
73+
74+
// Type of compression to support (std, gzip, deflate, br). If no type is specified
75+
// then fasthttp's default compression types and its internal order of priority are used.
76+
//
77+
// Important: The first type in the list is the preferred type
78+
// irrespective of the ordering of types in the incoming client's Accept-Encoding header.
79+
// That is because fasthttp's CompressHandler() internally uses arbitrary
80+
// type ordering to compress the response. fastglue thus overrides the
81+
// Accept-Encoding header to only have the first type in this list.
82+
// For instance, if the list here is [zstd, br], and the incoming header is
83+
// [gzip, deflate, br, zstd], fastglue will overwrite the header to [zstd],
84+
// forcing fasthttp to compress the response using the preferred type here.
85+
Types []CompressionType
86+
}
87+
5688
// Fastglue is the "glue" wrapper over fasthttp and fasthttprouter.
5789
type Fastglue struct {
5890
Router *fasthttprouter.Router
5991
Server *fasthttp.Server
60-
context interface{}
6192
MatchedRoutePathParam string
62-
before []FastMiddleware
63-
after []FastMiddleware
93+
94+
context interface{}
95+
before []FastMiddleware
96+
after []FastMiddleware
97+
98+
opt Options
99+
}
100+
101+
type Options struct {
102+
CompressionOpt CompressionOpt
64103
}
65104

66105
// New creates and returns a new instance of Fastglue.
67-
func New() *Fastglue {
68-
return &Fastglue{
106+
func New(o Options) *Fastglue {
107+
f := &Fastglue{
69108
Router: fasthttprouter.New(),
109+
opt: o,
70110
}
111+
112+
return f
71113
}
72114

73115
// ListenAndServe is a wrapper for fasthttp.ListenAndServe. It takes a TCP address,
@@ -150,7 +192,7 @@ func (f *Fastglue) Shutdown(s *fasthttp.Server, shutdownComplete chan error) {
150192
// handler is the "proxy" abstraction that converts a fastglue handler into
151193
// a fasthttp handler and passes execution in and out.
152194
func (f *Fastglue) handler(h FastRequestHandler) func(*fasthttp.RequestCtx) {
153-
return func(ctx *fasthttp.RequestCtx) {
195+
handler := func(ctx *fasthttp.RequestCtx) {
154196
req := &Request{
155197
RequestCtx: ctx,
156198
Context: f.context,
@@ -172,7 +214,35 @@ func (f *Fastglue) handler(h FastRequestHandler) func(*fasthttp.RequestCtx) {
172214
}
173215
}
174216

217+
// If compression is enabled, override the response header to
218+
// the preferred type in the config.
219+
if f.opt.CompressionOpt.Enabled {
220+
for _, typ := range f.opt.CompressionOpt.Types {
221+
t := string(typ)
222+
// If the preferred type is in the client's Accept-Encoding header,
223+
// overwrite the request header to only have this type, forcing
224+
// fasthttp.CompressHandler() to compress the response using it.
225+
// This is because fasthttp internally does not respect the order
226+
// in the client header and uses arbitrary ordering to compress the response.
227+
if ctx.Request.Header.HasAcceptEncoding(t) {
228+
ctx.Request.Header.Set("Accept-Encoding", t)
229+
break
230+
}
231+
}
232+
}
233+
}
234+
235+
// If compression is enabled, wrap the handler with fasthttp's CompressHandler
236+
// which automatically handles the compression logic.
237+
if f.opt.CompressionOpt.Enabled {
238+
// fasthttp's compression handlers are pretty bad. This particular handler
239+
// is the one that supports gzip|br|zstd|deflate.
240+
return fasthttp.CompressHandlerBrotliLevel(handler,
241+
fasthttp.CompressBrotliDefaultCompression,
242+
fasthttp.CompressDefaultCompression)
175243
}
244+
245+
return handler
176246
}
177247

178248
// Handler returns fastglue's central fasthttp handler that can be registered

0 commit comments

Comments
 (0)