Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions cmd/backend/dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"entgo.io/contrib/entgql"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/lru"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/database-playground/backend-v2/internal/auth"
"github.com/database-playground/backend-v2/internal/config"
"github.com/database-playground/backend-v2/internal/events"
"github.com/database-playground/backend-v2/internal/graphql/apq"
"github.com/database-playground/backend-v2/internal/httputils"
"github.com/database-playground/backend-v2/internal/sqlrunner"
"github.com/database-playground/backend-v2/internal/submission"
Expand All @@ -44,8 +46,20 @@ func SqlRunner(cfg config.Config) *sqlrunner.SqlRunner {
return sqlrunner.NewSqlRunner(cfg.SqlRunner)
}

func ApqCache(redisClient rueidis.Client) graphql.Cache[string] {
return apq.NewCache(redisClient, 24*time.Hour)
}

// GqlgenHandler creates a gqlgen handler.
func GqlgenHandler(entClient *ent.Client, storage auth.Storage, sqlrunner *sqlrunner.SqlRunner, useraccount *useraccount.Context, eventService *events.EventService, submissionService *submission.SubmissionService) *handler.Server {
func GqlgenHandler(
entClient *ent.Client,
storage auth.Storage,
sqlrunner *sqlrunner.SqlRunner,
useraccount *useraccount.Context,
eventService *events.EventService,
submissionService *submission.SubmissionService,
apqCache graphql.Cache[string],
) *handler.Server {
srv := handler.New(graph.NewSchema(entClient, storage, sqlrunner, useraccount, eventService, submissionService))

srv.AddTransport(transport.Options{})
Expand All @@ -57,7 +71,7 @@ func GqlgenHandler(entClient *ent.Client, storage auth.Storage, sqlrunner *sqlru
srv.Use(entgql.Transactioner{TxOpener: entClient})
srv.Use(extension.Introspection{})
srv.Use(extension.AutomaticPersistedQuery{
Cache: lru.New[string](100),
Cache: apqCache,
})

srv.SetErrorPresenter(graph.NewErrorPresenter())
Expand Down Expand Up @@ -86,7 +100,12 @@ func AuthService(entClient *ent.Client, storage auth.Storage, config config.Conf
}

// GinEngine creates a gin engine.
func GinEngine(services []httpapi.Service, authStorage auth.Storage, gqlgenHandler *handler.Server, cfg config.Config) *gin.Engine {
func GinEngine(
services []httpapi.Service,
authStorage auth.Storage,
gqlgenHandler *handler.Server,
cfg config.Config,
) *gin.Engine {
engine := gin.New()

if err := engine.SetTrustedProxies(cfg.TrustProxies); err != nil {
Expand Down
1 change: 1 addition & 0 deletions cmd/backend/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func main() {
UserAccountContext,
EventService,
SubmissionService,
ApqCache,
AnnotateService(AuthService),
GqlgenHandler,
fx.Annotate(
Expand Down
46 changes: 46 additions & 0 deletions internal/graphql/apq/apq.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Package apq implements Apollo Client's Automatic Persisted Queries.
// https://gqlgen.com/reference/apq/
package apq

import (
"context"
"log/slog"
"time"

"github.com/99designs/gqlgen/graphql"
"github.com/redis/rueidis"
)

type Cache struct {
client rueidis.Client
ttl time.Duration
}

const redisApqPrefix = "apq:"

func NewCache(client rueidis.Client, ttl time.Duration) *Cache {
return &Cache{client: client, ttl: ttl}
}

func (c *Cache) Get(ctx context.Context, query string) (string, bool) {
reply, err := c.client.Do(ctx, c.client.B().Get().Key(redisApqPrefix+query).Build()).ToString()
if err != nil {
if rueidis.IsRedisNil(err) {
return "", false
}

slog.Warn("error getting apq from cache", "error", err, "query", query)
return "", false
}

return reply, true
}

func (c *Cache) Add(ctx context.Context, query string, value string) {
err := c.client.Do(ctx, c.client.B().Set().Key(redisApqPrefix+query).Value(value).Ex(c.ttl).Build()).Error()
if err != nil {
slog.Warn("error adding apq to cache", "error", err, "query", query)
}
}

var _ graphql.Cache[string] = &Cache{}