-
Notifications
You must be signed in to change notification settings - Fork 14
/
gin.go
125 lines (104 loc) · 3.16 KB
/
gin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package hitrix
import (
"bytes"
"context"
"errors"
"fmt"
"io/ioutil"
"runtime/debug"
"time"
"github.com/coretrix/hitrix/service"
"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"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/gin-contrib/timeout"
"github.com/gin-gonic/gin"
)
type GinInitHandler func(ginEngine *gin.Engine)
type GQLServerInitHandler func(server *handler.Server)
func contextToContextMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
body, err := c.GetRawData()
if err != nil {
panic(err)
}
c.Request.Body = ioutil.NopCloser(bytes.NewReader(body))
ctx := context.WithValue(c.Request.Context(), service.GinKey, c)
ctx = context.WithValue(ctx, service.RequestBodyKey, body)
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
func InitGin(server graphql.ExecutableSchema, ginInitHandler GinInitHandler, gqlServerInitHandler GQLServerInitHandler) *gin.Engine {
app := service.DI().App()
if app.IsInProdMode() {
gin.SetMode(gin.ReleaseMode)
} else if app.IsInTestMode() {
gin.SetMode(gin.TestMode)
}
ginEngine := gin.New()
if !app.IsInProdMode() {
ginEngine.Use(gin.Logger())
}
ginEngine.Use(recovery())
ginEngine.Use(contextToContextMiddleware())
if ginInitHandler != nil {
ginInitHandler(ginEngine)
}
if app.DevPanel != nil {
devRouter := app.DevPanel.Router
devRouter(ginEngine)
}
if server != nil {
ginEngine.POST("/query", timeout.New(timeout.WithTimeout(10*time.Second), timeout.WithHandler(graphqlHandler(server, gqlServerInitHandler))))
ginEngine.GET("/", playgroundHandler())
}
return ginEngine
}
func graphqlHandler(server graphql.ExecutableSchema, gqlServerInitHandler GQLServerInitHandler) gin.HandlerFunc {
h := handler.New(server)
h.AddTransport(transport.Websocket{
KeepAlivePingInterval: 10 * time.Second,
})
h.AddTransport(transport.Options{})
h.AddTransport(transport.POST{})
h.SetQueryCache(lru.New(1000))
h.Use(extension.Introspection{})
h.Use(extension.AutomaticPersistedQuery{
Cache: lru.New(100),
})
h.SetRecoverFunc(func(ctx context.Context, err interface{}) error {
var message string
asErr, is := err.(error)
if is {
message = asErr.Error()
} else {
message = fmt.Sprint(err)
}
errorMessage := message + "\n" + string(debug.Stack())
errorLogger, has := service.DI().ErrorLogger()
if has {
ginContext := ctx.Value(service.GinKey).(*gin.Context)
requestBody := ctx.Value(service.RequestBodyKey).([]byte)
ginContext.Request.Body = ioutil.NopCloser(bytes.NewReader(requestBody))
errorLogger.LogErrorWithRequest(ginContext, errors.New(errorMessage))
}
return errors.New("internal server error")
})
if gqlServerInitHandler != nil {
gqlServerInitHandler(h)
}
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
func playgroundHandler() gin.HandlerFunc {
h := playground.Handler("GraphQL", "/query")
return func(c *gin.Context) {
c.Writer.Header().Add("X-Robots-Tag", "noindex")
h.ServeHTTP(c.Writer, c.Request)
}
}