Skip to content

Commit 5350516

Browse files
committed
feat: allow forcing cache control header
1 parent 5326ca5 commit 5350516

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,31 @@ func main() {
6464
srv = cache.Middleware(srv)
6565
// ... do more things
6666
}
67-
````
67+
```
6868

6969
Doing it, Gqlgen write the lowest max-age defined in cacheControl extensions.
7070

7171
For more informations, see `_example` folder.
72+
73+
### Force cache control in case of error
74+
75+
By default, any existing cache hints will not result in a Cache-Control header in case of an error.
76+
77+
It's possible to force it by adding a `forceCacheControl` key with a `true` value.
78+
79+
80+
```go
81+
func (h *handler) GraphqlHandler() gin.HandlerFunc {
82+
// ... setup gqlgen/graphql/handler
83+
// ... setup server
84+
srv.Use(cache.Extension{})
85+
cachedServer := cache.Middleware(srv)
86+
87+
return func(c *gin.Context) {
88+
ctx := context.WithValue(c.Request.Context(), "forceCacheControl", true)
89+
c.Request = c.Request.WithContext(ctx)
90+
91+
cachedServer.ServeHTTP(c.Writer, c.Request)
92+
}
93+
}
94+
````

cache/context.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package cache
2+
3+
import "context"
4+
5+
type contextKey string
6+
7+
const forceCacheControlKey = contextKey("forceCacheControl")
8+
9+
// ContextWithForceCacheControl creates a new context with the forceCacheControl option.
10+
func ContextWithForceCacheControl(ctx context.Context, forceCacheControl bool) context.Context {
11+
return context.WithValue(ctx, forceCacheControlKey, forceCacheControl)
12+
}

cache/context_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package cache
2+
3+
import (
4+
"context"
5+
"reflect"
6+
"testing"
7+
)
8+
9+
func TestContextWithForceCacheControl(t *testing.T) {
10+
type args struct {
11+
ctx context.Context
12+
forceCacheControl bool
13+
}
14+
tests := []struct {
15+
name string
16+
args args
17+
want context.Context
18+
}{
19+
{
20+
"forceCacheControl is false",
21+
args{context.Background(), false},
22+
context.WithValue(context.Background(), forceCacheControlKey, false),
23+
},
24+
{
25+
"valid key and value forceCacheControl",
26+
args{context.Background(), true},
27+
context.WithValue(context.Background(), forceCacheControlKey, true),
28+
},
29+
}
30+
for _, tt := range tests {
31+
t.Run(tt.name, func(t *testing.T) {
32+
if got := ContextWithForceCacheControl(tt.args.ctx, tt.args.forceCacheControl); !reflect.DeepEqual(got, tt.want) {
33+
t.Errorf("ContextWithForceCacheControl() = %v, want %v", got, tt.want)
34+
}
35+
})
36+
}
37+
}

cache/middleware.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ func (c responseWriter) Header() http.Header {
4040
}
4141

4242
func (c responseWriter) Write(bytes []byte) (int, error) {
43+
forceCacheControl, _ := c.r.Context().Value(forceCacheControlKey).(bool)
44+
4345
if c.w.Header().Get("Cache-Control") == "" {
4446
resp := graphql.Response{}
4547
err := json.Unmarshal(bytes, &resp)
4648
if err == nil {
47-
writeCacheControl(c.r.Context(), c.w, &resp)
49+
writeCacheControl(c.r.Context(), c.w, &resp, forceCacheControl)
4850
}
4951
}
5052

@@ -55,8 +57,8 @@ func (c responseWriter) WriteHeader(statusCode int) {
5557
c.w.WriteHeader(statusCode)
5658
}
5759

58-
func writeCacheControl(ctx context.Context, w http.ResponseWriter, response *graphql.Response) {
59-
if len(response.Errors) > 0 {
60+
func writeCacheControl(ctx context.Context, w http.ResponseWriter, response *graphql.Response, forceCacheControl bool) {
61+
if len(response.Errors) > 0 && !forceCacheControl {
6062
return
6163
}
6264

0 commit comments

Comments
 (0)