github.com/niko0xdev/gqlgen@v0.17.55-0.20240120102243-2ecff98c3e37/handler/handler.go (about)

     1  package handler
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/gorilla/websocket"
     9  
    10  	"github.com/niko0xdev/gqlgen/graphql"
    11  	"github.com/niko0xdev/gqlgen/graphql/handler"
    12  	"github.com/niko0xdev/gqlgen/graphql/handler/extension"
    13  	"github.com/niko0xdev/gqlgen/graphql/handler/lru"
    14  	"github.com/niko0xdev/gqlgen/graphql/handler/transport"
    15  	"github.com/niko0xdev/gqlgen/graphql/playground"
    16  )
    17  
    18  // Deprecated: switch to graphql/handler.New
    19  func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
    20  	var cfg Config
    21  	cfg.cacheSize = 1000
    22  
    23  	for _, option := range options {
    24  		option(&cfg)
    25  	}
    26  
    27  	srv := handler.New(exec)
    28  
    29  	srv.AddTransport(transport.Websocket{
    30  		Upgrader:              cfg.upgrader,
    31  		InitFunc:              cfg.websocketInitFunc,
    32  		KeepAlivePingInterval: cfg.connectionKeepAlivePingInterval,
    33  		PingPongInterval:      cfg.connectionPingPongInterval,
    34  	})
    35  	srv.AddTransport(transport.Options{})
    36  	srv.AddTransport(transport.GET{})
    37  	srv.AddTransport(transport.POST{})
    38  	srv.AddTransport(transport.MultipartForm{
    39  		MaxUploadSize: cfg.uploadMaxSize,
    40  		MaxMemory:     cfg.uploadMaxMemory,
    41  	})
    42  
    43  	if cfg.cacheSize != 0 {
    44  		srv.SetQueryCache(lru.New(cfg.cacheSize))
    45  	}
    46  	if cfg.recover != nil {
    47  		srv.SetRecoverFunc(cfg.recover)
    48  	}
    49  	if cfg.errorPresenter != nil {
    50  		srv.SetErrorPresenter(cfg.errorPresenter)
    51  	}
    52  	for _, hook := range cfg.fieldHooks {
    53  		srv.AroundFields(hook)
    54  	}
    55  	for _, hook := range cfg.requestHooks {
    56  		srv.AroundResponses(hook)
    57  	}
    58  	if cfg.complexityLimit != 0 {
    59  		srv.Use(extension.FixedComplexityLimit(cfg.complexityLimit))
    60  	} else if cfg.complexityLimitFunc != nil {
    61  		srv.Use(&extension.ComplexityLimit{
    62  			Func: func(ctx context.Context, rc *graphql.OperationContext) int {
    63  				return cfg.complexityLimitFunc(graphql.WithOperationContext(ctx, rc))
    64  			},
    65  		})
    66  	}
    67  	if !cfg.disableIntrospection {
    68  		srv.Use(extension.Introspection{})
    69  	}
    70  	if cfg.apqCache != nil {
    71  		srv.Use(extension.AutomaticPersistedQuery{Cache: apqAdapter{cfg.apqCache}})
    72  	}
    73  	return srv.ServeHTTP
    74  }
    75  
    76  // Deprecated: switch to graphql/handler.New
    77  type Config struct {
    78  	cacheSize                       int
    79  	upgrader                        websocket.Upgrader
    80  	websocketInitFunc               transport.WebsocketInitFunc
    81  	connectionKeepAlivePingInterval time.Duration
    82  	connectionPingPongInterval      time.Duration
    83  	recover                         graphql.RecoverFunc
    84  	errorPresenter                  graphql.ErrorPresenterFunc
    85  	fieldHooks                      []graphql.FieldMiddleware
    86  	requestHooks                    []graphql.ResponseMiddleware
    87  	complexityLimit                 int
    88  	complexityLimitFunc             func(ctx context.Context) int
    89  	disableIntrospection            bool
    90  	uploadMaxMemory                 int64
    91  	uploadMaxSize                   int64
    92  	apqCache                        PersistedQueryCache
    93  }
    94  
    95  // Deprecated: switch to graphql/handler.New
    96  type Option func(cfg *Config)
    97  
    98  // Deprecated: switch to graphql/handler.New
    99  func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
   100  	return func(cfg *Config) {
   101  		cfg.upgrader = upgrader
   102  	}
   103  }
   104  
   105  // Deprecated: switch to graphql/handler.New
   106  func RecoverFunc(recover graphql.RecoverFunc) Option {
   107  	return func(cfg *Config) {
   108  		cfg.recover = recover
   109  	}
   110  }
   111  
   112  // ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides
   113  // a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default
   114  // implementation in graphql.DefaultErrorPresenter for an example.
   115  // Deprecated: switch to graphql/handler.New
   116  func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
   117  	return func(cfg *Config) {
   118  		cfg.errorPresenter = f
   119  	}
   120  }
   121  
   122  // IntrospectionEnabled = false will forbid clients from calling introspection endpoints. Can be useful in prod when you don't
   123  // want clients introspecting the full schema.
   124  // Deprecated: switch to graphql/handler.New
   125  func IntrospectionEnabled(enabled bool) Option {
   126  	return func(cfg *Config) {
   127  		cfg.disableIntrospection = !enabled
   128  	}
   129  }
   130  
   131  // ComplexityLimit sets a maximum query complexity that is allowed to be executed.
   132  // If a query is submitted that exceeds the limit, a 422 status code will be returned.
   133  // Deprecated: switch to graphql/handler.New
   134  func ComplexityLimit(limit int) Option {
   135  	return func(cfg *Config) {
   136  		cfg.complexityLimit = limit
   137  	}
   138  }
   139  
   140  // ComplexityLimitFunc allows you to define a function to dynamically set the maximum query complexity that is allowed
   141  // to be executed.
   142  // If a query is submitted that exceeds the limit, a 422 status code will be returned.
   143  // Deprecated: switch to graphql/handler.New
   144  func ComplexityLimitFunc(complexityLimitFunc func(ctx context.Context) int) Option {
   145  	return func(cfg *Config) {
   146  		cfg.complexityLimitFunc = complexityLimitFunc
   147  	}
   148  }
   149  
   150  // ResolverMiddleware allows you to define a function that will be called around every resolver,
   151  // useful for logging.
   152  // Deprecated: switch to graphql/handler.New
   153  func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
   154  	return func(cfg *Config) {
   155  		cfg.fieldHooks = append(cfg.fieldHooks, middleware)
   156  	}
   157  }
   158  
   159  // RequestMiddleware allows you to define a function that will be called around the root request,
   160  // after the query has been parsed. This is useful for logging
   161  // Deprecated: switch to graphql/handler.New
   162  func RequestMiddleware(middleware graphql.ResponseMiddleware) Option {
   163  	return func(cfg *Config) {
   164  		cfg.requestHooks = append(cfg.requestHooks, middleware)
   165  	}
   166  }
   167  
   168  // WebsocketInitFunc is called when the server receives connection init message from the client.
   169  // This can be used to check initial payload to see whether to accept the websocket connection.
   170  // Deprecated: switch to graphql/handler.New
   171  func WebsocketInitFunc(websocketInitFunc transport.WebsocketInitFunc) Option {
   172  	return func(cfg *Config) {
   173  		cfg.websocketInitFunc = websocketInitFunc
   174  	}
   175  }
   176  
   177  // CacheSize sets the maximum size of the query cache.
   178  // If size is less than or equal to 0, the cache is disabled.
   179  // Deprecated: switch to graphql/handler.New
   180  func CacheSize(size int) Option {
   181  	return func(cfg *Config) {
   182  		cfg.cacheSize = size
   183  	}
   184  }
   185  
   186  // UploadMaxSize sets the maximum number of bytes used to parse a request body
   187  // as multipart/form-data.
   188  // Deprecated: switch to graphql/handler.New
   189  func UploadMaxSize(size int64) Option {
   190  	return func(cfg *Config) {
   191  		cfg.uploadMaxSize = size
   192  	}
   193  }
   194  
   195  // UploadMaxMemory sets the maximum number of bytes used to parse a request body
   196  // as multipart/form-data in memory, with the remainder stored on disk in
   197  // temporary files.
   198  // Deprecated: switch to graphql/handler.New
   199  func UploadMaxMemory(size int64) Option {
   200  	return func(cfg *Config) {
   201  		cfg.uploadMaxMemory = size
   202  	}
   203  }
   204  
   205  // WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior.
   206  // By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval
   207  // duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive
   208  // altogether.
   209  // Deprecated: switch to graphql/handler.New
   210  func WebsocketKeepAliveDuration(duration time.Duration) Option {
   211  	return func(cfg *Config) {
   212  		cfg.connectionKeepAlivePingInterval = duration
   213  	}
   214  }
   215  
   216  func WebsocketPingPongDuration(duration time.Duration) Option {
   217  	return func(cfg *Config) {
   218  		cfg.connectionPingPongInterval = duration
   219  	}
   220  }
   221  
   222  // Add cache that will hold queries for automatic persisted queries (APQ)
   223  // Deprecated: switch to graphql/handler.New
   224  func EnablePersistedQueryCache(cache PersistedQueryCache) Option {
   225  	return func(cfg *Config) {
   226  		cfg.apqCache = cache
   227  	}
   228  }
   229  
   230  func GetInitPayload(ctx context.Context) transport.InitPayload {
   231  	return transport.GetInitPayload(ctx)
   232  }
   233  
   234  type apqAdapter struct {
   235  	PersistedQueryCache
   236  }
   237  
   238  func (a apqAdapter) Get(ctx context.Context, key string) (value interface{}, ok bool) {
   239  	return a.PersistedQueryCache.Get(ctx, key)
   240  }
   241  
   242  func (a apqAdapter) Add(ctx context.Context, key string, value interface{}) {
   243  	a.PersistedQueryCache.Add(ctx, key, value.(string))
   244  }
   245  
   246  type PersistedQueryCache interface {
   247  	Add(ctx context.Context, hash string, query string)
   248  	Get(ctx context.Context, hash string) (string, bool)
   249  }
   250  
   251  // Deprecated: use playground.Handler instead
   252  func Playground(title string, endpoint string) http.HandlerFunc {
   253  	return playground.Handler(title, endpoint)
   254  }
   255  
   256  // Deprecated: use transport.InitPayload instead
   257  type InitPayload = transport.InitPayload