This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
backend/internal/graphql/delivery/httpdelivery/http_handler.go

90 lines
2.5 KiB
Go

package httpdelivery
import (
"fmt"
"github.com/Kichiyaki/appmode"
"github.com/go-chi/chi/v5"
"github.com/pkg/errors"
"net/http"
"time"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/internal/graphql/querycomplexity"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/lru"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/playground"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/internal/graphql/directive"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
"gitea.dwysokinski.me/zdam-egzamin-zawodowy/backend/internal/graphql/resolvers"
)
const (
playgroundTTL = time.Hour / time.Second
graphqlEndpoint = "/graphql"
playgroundEndpoint = "/"
)
type Config struct {
Resolver *resolvers.Resolver
Directive *directive.Directive
}
func Attach(r chi.Router, cfg Config) error {
if cfg.Resolver == nil {
return errors.New("cfg.Resolver is required")
}
gqlHandler := graphqlHandler(prepareConfig(cfg.Resolver, cfg.Directive))
r.Get(graphqlEndpoint, gqlHandler)
r.Post(graphqlEndpoint, gqlHandler)
if appmode.Equals(appmode.DevelopmentMode) {
r.Get(playgroundEndpoint, playgroundHandler())
}
return nil
}
func graphqlHandler(cfg generated.Config) http.HandlerFunc {
srv := handler.New(generated.NewExecutableSchema(cfg))
srv.AddTransport(transport.GET{})
srv.AddTransport(transport.POST{})
srv.AddTransport(transport.MultipartForm{
MaxUploadSize: 32 << 18,
MaxMemory: 32 << 18,
})
srv.Use(extension.AutomaticPersistedQuery{
Cache: lru.New(100),
})
srv.SetQueryCache(lru.New(100))
srv.Use(querycomplexity.GetComplexityLimitExtension())
if appmode.Equals(appmode.DevelopmentMode) {
srv.Use(extension.Introspection{})
}
return func(w http.ResponseWriter, r *http.Request) {
r.Header.Add("Cache-Control", "no-store, must-revalidate")
srv.ServeHTTP(w, r)
}
}
func playgroundHandler() http.HandlerFunc {
h := playground.Handler("Playground", graphqlEndpoint)
return func(w http.ResponseWriter, r *http.Request) {
r.Header.Add("Cache-Control", fmt.Sprintf(`public, max-age=%d`, playgroundTTL))
h.ServeHTTP(w, r)
}
}
func prepareConfig(r *resolvers.Resolver, d *directive.Directive) generated.Config {
cfg := generated.Config{
Resolvers: r,
Complexity: querycomplexity.GetComplexityRoot(),
}
cfg.Directives.Authenticated = d.Authenticated
cfg.Directives.HasRole = d.HasRole
return cfg
}