Skip to content

Commit 7c66f36

Browse files
raphaabrasilRaphael Brasil
andauthored
Use graphql.Register func to register cacheControl plugin (#5)
* fix: register extension using graphql.RegisterExtension func * refactor: creates an specific type for context key and reorganize declarations --------- Co-authored-by: Raphael Brasil <[email protected]>
1 parent c1e18ca commit 7c66f36

File tree

3 files changed

+73
-68
lines changed

3 files changed

+73
-68
lines changed

cache/cache.go

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,35 @@ import (
99
"github.com/vektah/gqlparser/v2/ast"
1010
)
1111

12-
type Scope string
12+
type (
13+
Scope string
14+
15+
ctxKey string
16+
17+
OverallCachePolicy struct {
18+
MaxAge float64
19+
Scope Scope
20+
}
21+
22+
CacheControlExtension struct {
23+
Version int `json:"version"`
24+
Hints []Hint `json:"hints"`
25+
mu sync.Mutex
26+
}
27+
28+
Hint struct {
29+
Path ast.Path `json:"path"`
30+
MaxAge float64 `json:"maxAge"`
31+
Scope Scope `json:"scope"`
32+
}
33+
)
1334

1435
const (
1536
ScopePublic = Scope("PUBLIC")
1637
ScopePrivate = Scope("PRIVATE")
17-
)
1838

19-
type Hint struct {
20-
Path ast.Path `json:"path"`
21-
MaxAge float64 `json:"maxAge"`
22-
Scope Scope `json:"scope"`
23-
}
24-
25-
type OverallCachePolicy struct {
26-
MaxAge float64
27-
Scope Scope
28-
}
29-
30-
type CacheControlExtension struct {
31-
Version int `json:"version"`
32-
Hints []Hint `json:"hints"`
33-
mu sync.Mutex
34-
}
39+
cacheCtxKey ctxKey = "key"
40+
)
3541

3642
func (cache *CacheControlExtension) AddHint(h Hint) {
3743
cache.mu.Lock()
@@ -65,15 +71,14 @@ func (cache *CacheControlExtension) OverallPolicy() OverallCachePolicy {
6571
}
6672
}
6773

68-
const key = "key"
69-
7074
func WithCacheControlExtension(ctx context.Context) context.Context {
7175
cache := &CacheControlExtension{Version: 1}
72-
return context.WithValue(ctx, key, cache)
76+
77+
return context.WithValue(ctx, cacheCtxKey, cache)
7378
}
7479

7580
func CacheControl(ctx context.Context) *CacheControlExtension {
76-
c := ctx.Value(key)
81+
c := ctx.Value(cacheCtxKey)
7782
if c, ok := c.(*CacheControlExtension); ok {
7883
return c
7984
}
@@ -82,7 +87,7 @@ func CacheControl(ctx context.Context) *CacheControlExtension {
8287
}
8388

8489
func SetHint(ctx context.Context, scope Scope, maxAge time.Duration) {
85-
c := ctx.Value(key)
90+
c := ctx.Value(cacheCtxKey)
8691
if c, ok := c.(*CacheControlExtension); ok {
8792
c.AddHint(Hint{
8893
Path: graphql.GetFieldContext(ctx).Path(),

cache/extension.go

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88

99
type Extension struct{}
1010

11-
var _ graphql.HandlerExtension = Extension{}
12-
var _ graphql.ResponseInterceptor = Extension{}
11+
var _ interface {
12+
graphql.HandlerExtension
13+
graphql.ResponseInterceptor
14+
} = Extension{}
1315

1416
func (c Extension) ExtensionName() string {
1517
return "cache"
@@ -20,23 +22,18 @@ func (c Extension) Validate(_ graphql.ExecutableSchema) error {
2022
}
2123

2224
func (c Extension) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
25+
if !graphql.HasOperationContext(ctx) {
26+
return next(ctx)
27+
}
28+
2329
cache := CacheControl(ctx)
2430
if cache == nil {
2531
ctx = WithCacheControlExtension(ctx)
26-
}
2732

28-
result := next(ctx)
29-
30-
if result != nil {
31-
cache := CacheControl(ctx)
32-
33-
if len(cache.Hints) > 0 {
34-
if result.Extensions == nil {
35-
result.Extensions = make(map[string]interface{})
36-
}
37-
result.Extensions["cacheControl"] = cache
38-
}
33+
cache = CacheControl(ctx)
3934
}
4035

41-
return result
36+
graphql.RegisterExtension(ctx, "cacheControl", cache)
37+
38+
return next(ctx)
4239
}

cache/extension_test.go

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,62 @@ func TestCache(t *testing.T) {
1818
})
1919

2020
t.Run("InterceptResponse", func(t *testing.T) {
21-
t.Run("should inject CacheControl in context", func(t *testing.T) {
22-
ext := Extension{}
21+
query := "query{latestPost {id}}"
2322

24-
ctx := context.Background()
25-
_ = ext.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
26-
cc := CacheControl(ctx)
27-
require.NotNil(t, cc)
28-
return &graphql.Response{}
29-
})
30-
})
23+
setupCtx := func(t *testing.T) context.Context {
24+
t.Helper()
25+
26+
ctxWithOperation := graphql.WithOperationContext(
27+
context.Background(),
28+
&graphql.OperationContext{
29+
RawQuery: query,
30+
})
3131

32-
t.Run("should not inject cacheControl extension", func(t *testing.T) {
32+
return graphql.WithResponseContext(
33+
ctxWithOperation,
34+
graphql.DefaultErrorPresenter,
35+
graphql.DefaultRecover,
36+
)
37+
}
38+
39+
t.Run("Does not try to register cacheControl extension if context is not part of an ongoing operation", func(t *testing.T) {
3340
ext := Extension{}
3441

35-
ctx := context.Background()
42+
ctx := context.TODO()
43+
3644
resp := ext.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
3745
return &graphql.Response{}
3846
})
3947

4048
require.Nil(t, resp.Extensions["cacheControl"])
4149
})
4250

43-
t.Run("should inject cacheControl extension", func(t *testing.T) {
51+
t.Run("Injects CacheControl in context", func(t *testing.T) {
4452
ext := Extension{}
4553

46-
ctx := context.Background()
47-
resp := ext.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
54+
ctx := setupCtx(t)
55+
56+
_ = ext.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
4857
cc := CacheControl(ctx)
49-
cc.AddHint(Hint{
50-
MaxAge: 10,
51-
Scope: ScopePrivate,
52-
})
58+
require.NotNil(t, cc)
5359
return &graphql.Response{}
5460
})
55-
56-
require.NotNil(t, resp.Extensions["cacheControl"])
5761
})
5862

59-
t.Run("should not override extensions", func(t *testing.T) {
63+
t.Run("Registers cacheControl extension around the graphql response operation", func(t *testing.T) {
6064
ext := Extension{}
6165

62-
ctx := context.Background()
66+
ctx := setupCtx(t)
67+
68+
var registeredExtensions map[string]interface{}
69+
6370
resp := ext.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
64-
return &graphql.Response{
65-
Extensions: map[string]interface{}{
66-
"foo": "bar",
67-
},
68-
}
71+
registeredExtensions = graphql.GetExtensions(ctx)
72+
73+
return &graphql.Response{Extensions: registeredExtensions}
6974
})
7075

71-
require.NotNil(t, resp.Extensions["foo"])
72-
require.Nil(t, resp.Extensions["cacheControl"])
76+
require.NotNil(t, resp.Extensions["cacheControl"])
7377
})
7478
})
75-
7679
}

0 commit comments

Comments
 (0)