@@ -4,11 +4,16 @@ import (
4
4
"context"
5
5
embed "embed"
6
6
"io/fs"
7
+ "time"
7
8
8
9
"github.com/99designs/gqlgen/graphql"
9
10
"github.com/99designs/gqlgen/graphql/handler"
11
+ "github.com/99designs/gqlgen/graphql/handler/extension"
12
+ "github.com/99designs/gqlgen/graphql/handler/lru"
10
13
"github.com/99designs/gqlgen/graphql/handler/transport"
11
14
"github.com/go-chi/chi/v5"
15
+ "github.com/vektah/gqlparser/v2/ast"
16
+ "github.com/vektah/gqlparser/v2/gqlerror"
12
17
13
18
"github.com/gnolang/tx-indexer/events"
14
19
"github.com/gnolang/tx-indexer/serve/graph/model"
@@ -19,7 +24,7 @@ import (
19
24
var examples embed.FS
20
25
21
26
func Setup (s storage.Storage , manager * events.Manager , m * chi.Mux ) * chi.Mux {
22
- srv := handler . NewDefaultServer (NewExecutableSchema (
27
+ srv := newGraphQueryServer (NewExecutableSchema (
23
28
Config {
24
29
Resolvers : NewResolver (s , manager ),
25
30
Directives : DirectiveRoot {
@@ -37,6 +42,25 @@ func Setup(s storage.Storage, manager *events.Manager, m *chi.Mux) *chi.Mux {
37
42
38
43
srv .AddTransport (& transport.Websocket {})
39
44
45
+ srv .AroundOperations (func (ctx context.Context , next graphql.OperationHandler ) graphql.ResponseHandler {
46
+ oc := graphql .GetOperationContext (ctx )
47
+ if oc .Operation != nil && oc .Operation .Operation == ast .Query {
48
+ if includesIntrospection (oc .Operation .SelectionSet ) {
49
+ return func (ctx context.Context ) * graphql.Response {
50
+ return & graphql.Response {
51
+ Errors : gqlerror.List {
52
+ & gqlerror.Error {
53
+ Message : "GraphQL introspection is disabled" ,
54
+ },
55
+ },
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ return next (ctx )
62
+ })
63
+
40
64
es , err := examplesToSlice ()
41
65
if err != nil {
42
66
panic (err )
@@ -68,3 +92,48 @@ func examplesToSlice() ([]string, error) {
68
92
69
93
return out , err
70
94
}
95
+
96
+ func newGraphQueryServer (es graphql.ExecutableSchema ) * handler.Server {
97
+ srv := handler .New (es )
98
+
99
+ srv .AddTransport (transport.Websocket {
100
+ KeepAlivePingInterval : 10 * time .Second ,
101
+ })
102
+ srv .AddTransport (transport.Options {})
103
+ srv .AddTransport (transport.GET {})
104
+ srv .AddTransport (transport.POST {})
105
+ srv .AddTransport (transport.MultipartForm {})
106
+
107
+ srv .SetQueryCache (lru.New [* ast.QueryDocument ](1000 ))
108
+
109
+ srv .Use (extension.AutomaticPersistedQuery {
110
+ Cache : lru.New [string ](100 ),
111
+ })
112
+
113
+ return srv
114
+ }
115
+
116
+ func includesIntrospection (selectionSet ast.SelectionSet ) bool {
117
+ for _ , selection := range selectionSet {
118
+ switch sel := selection .(type ) {
119
+ case * ast.Field :
120
+ if sel .Name == "__schema" || sel .Name == "__typename" {
121
+ return true
122
+ }
123
+
124
+ if includesIntrospection (sel .SelectionSet ) {
125
+ return true
126
+ }
127
+ case * ast.FragmentSpread :
128
+ if sel .Definition != nil && includesIntrospection (sel .Definition .SelectionSet ) {
129
+ return true
130
+ }
131
+ case * ast.InlineFragment :
132
+ if includesIntrospection (sel .SelectionSet ) {
133
+ return true
134
+ }
135
+ }
136
+ }
137
+
138
+ return false
139
+ }
0 commit comments