-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
120 lines (101 loc) · 3 KB
/
server.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
package gqlgenx
import (
"fmt"
"net/http"
"net/url"
"time"
"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/bearchit/goboost/graphql/voyager"
"github.com/creasty/defaults"
"github.com/go-chi/chi"
"github.com/go-playground/validator"
"github.com/rs/cors"
"github.com/bearchit/gqlgenx/graphiql"
)
type ServerOption struct {
Addr string `validate:"required" default:":8080"`
Endpoint string `validate:"required" default:"/graphql"`
GraphiQL *bool `validate:"required" default:"true"`
Playground *bool `validate:"required" default:"false"`
Voyager *bool `validate:"required" default:"true"`
Introspection *bool `validate:"required" default:"true"`
CORS *struct {
AllowedOrigins []string
AllowCredentials bool `default:"true"`
}
HealthCheck struct {
Path string `validate:"required" default:"/health_check"`
}
}
func (opt ServerOption) FullEndpoint() string {
u := url.URL{Scheme: "http", Host: opt.Addr, Path: opt.Endpoint}
return u.String()
}
func (opt ServerOption) BasePath() string {
u := url.URL{Scheme: "http", Host: opt.Addr}
return u.String()
}
type Server struct {
option ServerOption
handler http.Handler
}
func (s Server) Option() ServerOption {
return s.option
}
func (s Server) Serve() error {
return http.ListenAndServe(s.option.Addr, s.handler)
}
func NewServer(es graphql.ExecutableSchema, opt ServerOption) (*Server, error) {
if err := defaults.Set(&opt); err != nil {
return nil, fmt.Errorf("server option error: %w", err)
}
if err := validator.New().Struct(&opt); err != nil {
return nil, fmt.Errorf("server option error: %w", err)
}
srv := handler.New(es)
srv.AddTransport(transport.Websocket{
KeepAlivePingInterval: 10 * time.Second,
})
srv.AddTransport(transport.Options{})
srv.AddTransport(transport.GET{})
srv.AddTransport(transport.POST{})
srv.AddTransport(transport.MultipartForm{})
srv.SetQueryCache(lru.New(1000))
if *opt.Introspection {
srv.Use(extension.Introspection{})
}
srv.Use(extension.AutomaticPersistedQuery{
Cache: lru.New(100),
})
r := chi.NewRouter()
if opt.CORS != nil {
r.Use(cors.New(cors.Options{
AllowedOrigins: opt.CORS.AllowedOrigins,
AllowCredentials: opt.CORS.AllowCredentials,
}).Handler)
}
r.Get(opt.HealthCheck.Path, func(w http.ResponseWriter, req *http.Request) {
if _, err := w.Write([]byte("I'm healthy")); err != nil {
panic(err)
}
})
if *opt.GraphiQL {
r.Handle("/", graphiql.Handler("GraphiQL", opt.Endpoint))
}
if *opt.Playground {
r.Handle("/playground", playground.Handler("GraphQL Playground", opt.Endpoint))
}
if *opt.Voyager {
r.Handle("/voyager", voyager.Handler("GraphQL Voyager", opt.Endpoint))
}
r.Handle(opt.Endpoint, srv)
return &Server{
option: opt,
handler: r,
}, nil
}