Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support graphiql playground defaultQuery property #3266

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading