This repository has been archived by the owner on Feb 16, 2023. It is now read-only.
/
graphql.go
104 lines (92 loc) · 2.54 KB
/
graphql.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
package handle
import (
"context"
navErr "errors"
"github.com/gin-gonic/gin"
"github.com/graph-gophers/graphql-go"
"github.com/opentracing/opentracing-go"
"github.com/qeelyn/gin-contrib/auth"
"github.com/qeelyn/gin-contrib/tracing"
"github.com/qeelyn/go-common/logger"
"github.com/qeelyn/golang-starter-kit/gateway/app"
"github.com/qeelyn/golang-starter-kit/gateway/errors"
"github.com/qeelyn/golang-starter-kit/gateway/loader"
"github.com/qeelyn/golang-starter-kit/gateway/resolver"
"github.com/qeelyn/golang-starter-kit/gateway/schema"
"net/http"
"sync"
)
type query struct {
Query string `json:"query"`
OperationName string `json:"operationName"`
Variables map[string]interface{} `json:"variables"`
}
type request struct {
queries []query
isBatch bool
}
type GraphQL struct {
Schema *graphql.Schema
Loaders loader.Collection
CheckAccess *auth.CheckAccess
}
func ServeGraphqlResource(r *gin.RouterGroup) {
//tracer := graphql.Tracer(opentracing.GlobalTracer())
graphqlSchema := graphql.MustParseSchema(schema.GetRootSchema(), &resolver.Resolver{})
graphql.Logger(NewGraphqlLogger(app.Logger))
h := &GraphQL{
Schema: graphqlSchema,
Loaders: loader.NewLoaderCollection(),
CheckAccess: app.CheckAccessMiddleware,
}
r.POST("query", h.Query)
}
type graphqlLoggerAdapter struct {
logger *logger.Logger
}
func NewGraphqlLogger(l *logger.Logger) *graphqlLoggerAdapter {
return &graphqlLoggerAdapter{
logger: l,
}
}
func (t *graphqlLoggerAdapter) LogPanic(ctx context.Context, value interface{}) {
app.Logger.WithContext(ctx).Error(value.(string))
}
func (t *GraphQL) Query(c *gin.Context) {
req, err := parse(c.Request)
if err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
n := len(req.queries)
if n == 0 {
c.AbortWithError(http.StatusBadRequest, navErr.New("err-request"))
return
}
var (
ctx = t.Loaders.Attach(c)
responses = make([]*graphql.Response, n)
wg sync.WaitGroup
)
spanCtx, _ := tracing.SpanFromContext(c)
if spanCtx != nil {
span := opentracing.StartSpan(c.Request.RequestURI, opentracing.ChildOf(spanCtx))
ctx = opentracing.ContextWithSpan(ctx, span)
defer span.Finish()
}
wg.Add(n)
for i, q := range req.queries {
go func(i int, q query) {
res := t.Schema.Exec(ctx, q.Query, q.OperationName, q.Variables)
res.Errors = errors.Expand(res.Errors)
responses[i] = res
wg.Done()
}(i, q)
}
wg.Wait()
if req.isBatch {
c.JSON(200, responses)
} else if len(responses) > 0 {
c.JSON(200, responses[0])
}
}