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