graphql
graphql copied to clipboard
Setting header values (Cache)
I am trying to find a way to set header value (Cache control) How can it be done? I've noticed that even if I wrote own middleware, it's not possible(it does not have any effect) to set header after grapql invoke writeHeader in handler. I am passing my header values in context, but I cant not use it
Same issue. Any updates from your side?
@Aravind1411 The current solution that I am using - It allows to set header for specific query Please notice that it has some limitation as it is possible to join multiple queries in GQL.
{
queryA{ //may have cache 2min
bar
}
queryB {//may have cache 10min
bar
}
}
//schema.go
"fooQuery": headers(maxAge(600))(fooQuery)
var noStore = header.NoStore
var maxAge = header.MaxAge
func headers(headers ...http.Header) func(f *graphql.Field) *graphql.Field {
headerCfg := http.Header{}
for _, v := range headers {
for k := range v {
headerCfg.Set(k, v.Get(k))
}
}
return func(f *graphql.Field) *graphql.Field {
resolve := f.Resolve
f.Resolve = func(p graphql.ResolveParams) (interface{}, error) {
res, err := resolve(p)
if err == nil {
header.SetHeadersConfig(p.Context, headerCfg)
}
return res, err
}
return f
}
}
//header package
var headersCfgKey = contextKey("headersCfg")
type contextKey string
func HeadersConfigFromCtx(ctx context.Context) http.Header {
if c, ok := ctx.Value(headersCfgKey).(http.Header); ok {
return c
}
return nil
}
func SetHeadersConfig(ctx context.Context, header http.Header) {
cfg := HeadersConfigFromCtx(ctx)
if cfg == nil {
return
}
for k := range header {
cfg.Set(k, header.Get(k))
}
}
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rec := httptest.NewRecorder()
headers := http.Header{}
next.ServeHTTP(rec, r.WithContext(context.WithValue(r.Context(), headersCfgKey, headers)))
result := rec.Result()
for k := range result.Header {
w.Header().Set(k, result.Header.Get(k))
}
for k := range headers {
w.Header().Set(k, headers.Get(k))
}
w.WriteHeader(result.StatusCode)
if _, err := w.Write(rec.Body.Bytes()); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
})
}
func NoStore() http.Header {
h := http.Header{}
h.Set("Cache-Control", "no-store, max-age=0")
return h
}
func MaxAge(duration uint) http.Header {
h := http.Header{}
h.Set("Cache-Control", fmt.Sprintf("public, maxage=%d", duration))
return h
}
and use middleware to set headers
return server.Start(cancel, header.Middleware(r), host, port)