Skip to content

Commit 1e1c012

Browse files
authored
Merge branch 'master' into feature/graphiql
2 parents 6fa14a3 + 62f4eb5 commit 1e1c012

File tree

5 files changed

+140
-11
lines changed

5 files changed

+140
-11
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/graphql-go/handler
22

33
go 1.14
4+
5+
require github.com/graphql-go/graphql v0.8.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/graphql-go/graphql v0.8.1 h1:p7/Ou/WpmulocJeEx7wjQy611rtXGQaAcXGqanuMMgc=
2+
github.com/graphql-go/graphql v0.8.1/go.mod h1:nKiHzRM0qopJEwCITUuIsxk9PlVlwIiiI8pnJEhordQ=

graphcoolPlayground.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package handler
22

33
import (
4-
"fmt"
54
"html/template"
65
"net/http"
76
)
@@ -14,7 +13,7 @@ type playgroundData struct {
1413
}
1514

1615
// renderPlayground renders the Playground GUI
17-
func renderPlayground(w http.ResponseWriter, r *http.Request) {
16+
func renderPlayground(w http.ResponseWriter, r *http.Request, endpoint string, subscriptionEndpoint string) {
1817
t := template.New("Playground")
1918
t, err := t.Parse(graphcoolPlaygroundTemplate)
2019
if err != nil {
@@ -24,16 +23,14 @@ func renderPlayground(w http.ResponseWriter, r *http.Request) {
2423

2524
d := playgroundData{
2625
PlaygroundVersion: graphcoolPlaygroundVersion,
27-
Endpoint: r.URL.Path,
28-
SubscriptionEndpoint: fmt.Sprintf("ws://%v/subscriptions", r.Host),
26+
Endpoint: endpoint,
27+
SubscriptionEndpoint: subscriptionEndpoint,
2928
SetTitle: true,
3029
}
3130
err = t.ExecuteTemplate(w, "index", d)
3231
if err != nil {
3332
http.Error(w, err.Error(), http.StatusInternalServerError)
3433
}
35-
36-
return
3734
}
3835

3936
const graphcoolPlaygroundVersion = "1.5.2"

handler.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package handler
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"io/ioutil"
67
"net/http"
78
"net/url"
@@ -27,6 +28,7 @@ type Handler struct {
2728
pretty bool
2829
graphiql bool
2930
playground bool
31+
playgroundConfig *PlaygroundConfig
3032
rootObjectFn RootObjectFn
3133
resultCallbackFn ResultCallbackFn
3234
formatErrorFn func(err error) gqlerrors.FormattedError
@@ -162,7 +164,15 @@ func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *
162164
acceptHeader := r.Header.Get("Accept")
163165
_, raw := r.URL.Query()["raw"]
164166
if !raw && !strings.Contains(acceptHeader, "application/json") && strings.Contains(acceptHeader, "text/html") {
165-
renderPlayground(w, r)
167+
168+
endpoint := r.URL.Path
169+
subscriptionEndpoint := fmt.Sprintf("ws://%v/subscriptions", r.Host)
170+
if h.playgroundConfig != nil {
171+
endpoint = h.playgroundConfig.Endpoint
172+
subscriptionEndpoint = h.playgroundConfig.SubscriptionEndpoint
173+
}
174+
175+
renderPlayground(w, r, endpoint, subscriptionEndpoint)
166176
return
167177
}
168178
}
@@ -196,22 +206,29 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
196206
// RootObjectFn allows a user to generate a RootObject per request
197207
type RootObjectFn func(ctx context.Context, r *http.Request) map[string]interface{}
198208

209+
type PlaygroundConfig struct {
210+
Endpoint string
211+
SubscriptionEndpoint string
212+
}
213+
199214
type Config struct {
200215
Schema *graphql.Schema
201216
Pretty bool
202217
GraphiQL bool
203218
Playground bool
219+
PlaygroundConfig *PlaygroundConfig
204220
RootObjectFn RootObjectFn
205221
ResultCallbackFn ResultCallbackFn
206222
FormatErrorFn func(err error) gqlerrors.FormattedError
207223
}
208224

209225
func NewConfig() *Config {
210226
return &Config{
211-
Schema: nil,
212-
Pretty: true,
213-
GraphiQL: true,
214-
Playground: false,
227+
Schema: nil,
228+
Pretty: true,
229+
GraphiQL: true,
230+
Playground: false,
231+
PlaygroundConfig: nil,
215232
}
216233
}
217234

@@ -229,6 +246,7 @@ func New(p *Config) *Handler {
229246
pretty: p.Pretty,
230247
graphiql: p.GraphiQL,
231248
playground: p.Playground,
249+
playgroundConfig: p.PlaygroundConfig,
232250
rootObjectFn: p.RootObjectFn,
233251
resultCallbackFn: p.ResultCallbackFn,
234252
formatErrorFn: p.FormatErrorFn,

handler_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,113 @@ func TestHandler_BasicQuery_WithFormatErrorFn(t *testing.T) {
290290
t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result))
291291
}
292292
}
293+
294+
func TestPlaygroundWithDefaultConfig(t *testing.T) {
295+
query := graphql.NewObject(graphql.ObjectConfig{
296+
Name: "Query",
297+
Fields: graphql.Fields{
298+
"ping": &graphql.Field{
299+
Name: "ping",
300+
Type: graphql.String,
301+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
302+
return "OK", nil
303+
},
304+
},
305+
},
306+
})
307+
308+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
309+
Query: query,
310+
})
311+
if err != nil {
312+
t.Fatal(err)
313+
}
314+
315+
req, err := http.NewRequest("GET", "/graphql", nil)
316+
req.Header.Set("Accept", "text/html")
317+
if err != nil {
318+
t.Fatal(err)
319+
}
320+
321+
h := handler.New(&handler.Config{
322+
Schema: &schema,
323+
Playground: true,
324+
})
325+
326+
resp := httptest.NewRecorder()
327+
h.ContextHandler(context.Background(), resp, req)
328+
329+
if resp.Code != http.StatusOK {
330+
t.Fatalf("unexpected server response %v", resp.Code)
331+
}
332+
333+
expectedBodyContains := []string{
334+
"GraphQL Playground",
335+
`endpoint: "/graphql"`,
336+
`subscriptionEndpoint: "ws:///subscriptions"`,
337+
}
338+
respBody := resp.Body.String()
339+
340+
for _, e := range expectedBodyContains {
341+
if !strings.Contains(respBody, e) {
342+
t.Fatalf("wrong body, expected %s to contain %s", respBody, e)
343+
}
344+
}
345+
}
346+
347+
func TestPlaygroundWithCustomConfig(t *testing.T) {
348+
query := graphql.NewObject(graphql.ObjectConfig{
349+
Name: "Query",
350+
Fields: graphql.Fields{
351+
"ping": &graphql.Field{
352+
Name: "ping",
353+
Type: graphql.String,
354+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
355+
return "OK", nil
356+
},
357+
},
358+
},
359+
})
360+
361+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
362+
Query: query,
363+
})
364+
if err != nil {
365+
t.Fatal(err)
366+
}
367+
368+
req, err := http.NewRequest("GET", "/custom-path/graphql", nil)
369+
req.Header.Set("Accept", "text/html")
370+
if err != nil {
371+
t.Fatal(err)
372+
}
373+
374+
h := handler.New(&handler.Config{
375+
Schema: &schema,
376+
Playground: true,
377+
PlaygroundConfig: &handler.PlaygroundConfig{
378+
Endpoint: "/custom-path/graphql",
379+
SubscriptionEndpoint: "/custom-path/ws",
380+
},
381+
})
382+
383+
resp := httptest.NewRecorder()
384+
h.ContextHandler(context.Background(), resp, req)
385+
386+
if resp.Code != http.StatusOK {
387+
t.Fatalf("unexpected server response %v", resp.Code)
388+
}
389+
390+
expectedBodyContains := []string{
391+
"GraphQL Playground",
392+
`endpoint: "/custom-path/graphql"`,
393+
`subscriptionEndpoint: "/custom-path/ws"`,
394+
}
395+
respBody := resp.Body.String()
396+
397+
for _, e := range expectedBodyContains {
398+
if !strings.Contains(respBody, e) {
399+
t.Fatalf("wrong body, expected %s to contain %s", respBody, e)
400+
}
401+
}
402+
}

0 commit comments

Comments
 (0)