Skip to content

Commit

Permalink
feat: support graphiql defaultQuery property
Browse files Browse the repository at this point in the history
  • Loading branch information
molaga committed Sep 11, 2024
1 parent fda0539 commit 4a18eda
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 15 deletions.
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ Our [discord](https://discord.gg/DYEq3EMs4U) server is the best place to ask que

## Reporting Bugs and Issues

We use [GitHub Issues](https://github.com/99designs/gqlgen/issues) to track bugs, so please do a search before submitting to ensure your problem isn't already tracked.
We use [GitHub Issues](https://github.com/99designs/gqlgen/issues) to track bugs, so please do a search before submitting to ensure your problem isn't already tracked.

### New Issues

Please provide the expected and observed behaviours in your issue. A minimal GraphQL schema or configuration file should be provided where appropriate.

## Proposing a Change

If you intend to implement a feature for gqlgen, or make a non-trivial change to the current implementation, we recommend [first filing an issue](https://github.com/99designs/gqlgen/issues/new) marked with the `proposal` tag, so that the engineering team can provide guidance and feedback on the direction of an implementation. This also help ensure that other people aren't also working on the same thing.
If you intend to implement a feature for gqlgen, or make a non-trivial change to the current implementation, we recommend [first filing an issue](https://github.com/99designs/gqlgen/issues/new) marked with the `proposal` tag, so that the engineering team can provide guidance and feedback on the direction of an implementation. This also help ensure that other people aren't also working on the same thing.

Bug fixes are welcome and should come with appropriate test coverage.

New features should be made against the `next` branch.
New features should be made against the `master` branch.

### License

Expand Down
2 changes: 1 addition & 1 deletion graphql/playground/altair_playground.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ var altairPage = template.Must(template.New("altair").Parse(`<!doctype html>
</html>`))

// AltairHandler responsible for setting up the altair playground
func AltairHandler(title, endpoint string) http.HandlerFunc {
func AltairHandler(title, endpoint string, options ...func(*PlaygroundOpts)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
err := altairPage.Execute(w, map[string]any{
"title": title,
Expand Down
2 changes: 1 addition & 1 deletion graphql/playground/apollo_sandbox_playground_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func TestApolloSandboxHandler_Integrity(t *testing.T) {
testResourceIntegrity(t, func(title, endpoint string) http.HandlerFunc {
testResourceIntegrity(t, func(title, endpoint string, options ...func(*PlaygroundOpts)) http.HandlerFunc {
return ApolloSandboxHandler(title, endpoint)
})
}
2 changes: 1 addition & 1 deletion graphql/playground/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/stretchr/testify/require"
)

func testResourceIntegrity(t *testing.T, handler func(title, endpoint string) http.HandlerFunc) {
func testResourceIntegrity(t *testing.T, handler func(title, endpoint string, options ...func(*PlaygroundOpts)) http.HandlerFunc) {
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, "http://localhost:8080/", http.NoBody)
handler("example.org API", "/query").ServeHTTP(recorder, request)
Expand Down
50 changes: 41 additions & 9 deletions graphql/playground/playground.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
fetcher: fetcher,
isHeadersEditorEnabled: true,
shouldPersistHeaders: true,
headers: JSON.stringify(uiHeaders, null, 2)
headers: JSON.stringify(uiHeaders, null, 2),
defaultQuery: {{.defaultQuery}}
}),
document.getElementById('graphiql'),
);
Expand All @@ -84,24 +85,43 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
</html>
`))

// PlaygroundOpts contains options for configuring the GraphQL Playground
type PlaygroundOpts struct {
Title string
Endpoint string
DefaultQuery string
}

// WithDefaultQuery sets the default query for the playground
func WithDefaultQuery(query string) func(*PlaygroundOpts) {
return func(opts *PlaygroundOpts) {
opts.DefaultQuery = query
}
}

// Handler responsible for setting up the playground
func Handler(title, endpoint string) http.HandlerFunc {
return HandlerWithHeaders(title, endpoint, nil, nil)
func Handler(title, endpoint string, options ...func(*PlaygroundOpts)) http.HandlerFunc {
opts := initOpts(title, endpoint, options...)

return HandlerWithHeaders(opts.Title, opts.Endpoint, nil, nil, options...)
}

// HandlerWithHeaders sets up the playground.
// fetcherHeaders are used by the playground's fetcher instance and will not be visible in the UI.
// uiHeaders are default headers that will show up in the UI headers editor.
func HandlerWithHeaders(title, endpoint string, fetcherHeaders, uiHeaders map[string]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
func HandlerWithHeaders(title, endpoint string, fetcherHeaders, uiHeaders map[string]string, options ...func(*PlaygroundOpts)) http.HandlerFunc {
opts := initOpts(title, endpoint, options...)

return func(w http.ResponseWriter, _ *http.Request) {
w.Header().Add("Content-Type", "text/html; charset=UTF-8")
err := page.Execute(w, map[string]any{
"title": title,
"endpoint": endpoint,
"title": opts.Title,
"endpoint": opts.Endpoint,
"fetcherHeaders": fetcherHeaders,
"uiHeaders": uiHeaders,
"endpointIsAbsolute": endpointHasScheme(endpoint),
"subscriptionEndpoint": getSubscriptionEndpoint(endpoint),
"endpointIsAbsolute": endpointHasScheme(opts.Endpoint),
"subscriptionEndpoint": getSubscriptionEndpoint(opts.Endpoint),
"defaultQuery": opts.DefaultQuery,
"version": "3.0.6",
"cssSRI": "sha256-wTzfn13a+pLMB5rMeysPPR1hO7x0SwSeQI+cnw7VdbE=",
"jsSRI": "sha256-eNxH+Ah7Z9up9aJYTQycgyNuy953zYZwE9Rqf5rH+r4=",
Expand All @@ -114,6 +134,18 @@ func HandlerWithHeaders(title, endpoint string, fetcherHeaders, uiHeaders map[st
}
}

// initOpts initializes the playground options with the given title and endpoint.
func initOpts(title, endpoint string, optFuncs ...func(*PlaygroundOpts)) *PlaygroundOpts {
opts := &PlaygroundOpts{
Title: title,
Endpoint: endpoint,
}
for _, optFunc := range optFuncs {
optFunc(opts)
}
return opts
}

// endpointHasScheme checks if the endpoint has a scheme.
func endpointHasScheme(endpoint string) bool {
u, err := url.Parse(endpoint)
Expand Down

0 comments on commit 4a18eda

Please sign in to comment.