graphiql.go

  1package handler
  2
  3import (
  4	"encoding/json"
  5	"html/template"
  6	"net/http"
  7
  8	"github.com/graphql-go/graphql"
  9)
 10
 11// page is the page data structure of the rendered GraphiQL page
 12type graphiqlPage struct {
 13	GraphiqlVersion string
 14	QueryString     string
 15	ResultString    string
 16	VariablesString string
 17	OperationName   string
 18}
 19
 20// renderGraphiQL renders the GraphiQL GUI
 21func renderGraphiQL(w http.ResponseWriter, params graphql.Params) {
 22	t := template.New("GraphiQL")
 23	t, err := t.Parse(graphiqlTemplate)
 24	if err != nil {
 25		http.Error(w, err.Error(), http.StatusInternalServerError)
 26		return
 27	}
 28
 29	// Create variables string
 30	vars, err := json.MarshalIndent(params.VariableValues, "", "  ")
 31	if err != nil {
 32		http.Error(w, err.Error(), http.StatusInternalServerError)
 33		return
 34	}
 35	varsString := string(vars)
 36	if varsString == "null" {
 37		varsString = ""
 38	}
 39
 40	// Create result string
 41	var resString string
 42	if params.RequestString == "" {
 43		resString = ""
 44	} else {
 45		result, err := json.MarshalIndent(graphql.Do(params), "", "  ")
 46		if err != nil {
 47			http.Error(w, err.Error(), http.StatusInternalServerError)
 48			return
 49		}
 50		resString = string(result)
 51	}
 52
 53	p := graphiqlPage{
 54		GraphiqlVersion: graphiqlVersion,
 55		QueryString:     params.RequestString,
 56		ResultString:    resString,
 57		VariablesString: varsString,
 58		OperationName:   params.OperationName,
 59	}
 60
 61	err = t.ExecuteTemplate(w, "index", p)
 62	if err != nil {
 63		http.Error(w, err.Error(), http.StatusInternalServerError)
 64	}
 65	return
 66}
 67
 68// graphiqlVersion is the current version of GraphiQL
 69const graphiqlVersion = "0.11.3"
 70
 71// tmpl is the page template to render GraphiQL
 72const graphiqlTemplate = `
 73{{ define "index" }}
 74<!--
 75The request to this GraphQL server provided the header "Accept: text/html"
 76and as a result has been presented GraphiQL - an in-browser IDE for
 77exploring GraphQL.
 78
 79If you wish to receive JSON, provide the header "Accept: application/json" or
 80add "&raw" to the end of the URL within a browser.
 81-->
 82<!DOCTYPE html>
 83<html>
 84<head>
 85  <meta charset="utf-8" />
 86  <title>GraphiQL</title>
 87  <meta name="robots" content="noindex" />
 88  <style>
 89    html, body {
 90      height: 100%;
 91      margin: 0;
 92      overflow: hidden;
 93      width: 100%;
 94    }
 95  </style>
 96  <link href="//cdn.jsdelivr.net/npm/graphiql@{{ .GraphiqlVersion }}/graphiql.css" rel="stylesheet" />
 97  <script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
 98  <script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
 99  <script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
100  <script src="//cdn.jsdelivr.net/npm/graphiql@{{ .GraphiqlVersion }}/graphiql.min.js"></script>
101</head>
102<body>
103  <script>
104    // Collect the URL parameters
105    var parameters = {};
106    window.location.search.substr(1).split('&').forEach(function (entry) {
107      var eq = entry.indexOf('=');
108      if (eq >= 0) {
109        parameters[decodeURIComponent(entry.slice(0, eq))] =
110          decodeURIComponent(entry.slice(eq + 1));
111      }
112    });
113
114    // Produce a Location query string from a parameter object.
115    function locationQuery(params) {
116      return '?' + Object.keys(params).filter(function (key) {
117        return Boolean(params[key]);
118      }).map(function (key) {
119        return encodeURIComponent(key) + '=' +
120          encodeURIComponent(params[key]);
121      }).join('&');
122    }
123
124    // Derive a fetch URL from the current URL, sans the GraphQL parameters.
125    var graphqlParamNames = {
126      query: true,
127      variables: true,
128      operationName: true
129    };
130
131    var otherParams = {};
132    for (var k in parameters) {
133      if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) {
134        otherParams[k] = parameters[k];
135      }
136    }
137    var fetchURL = locationQuery(otherParams);
138
139    // Defines a GraphQL fetcher using the fetch API.
140    function graphQLFetcher(graphQLParams) {
141      return fetch(fetchURL, {
142        method: 'post',
143        headers: {
144          'Accept': 'application/json',
145          'Content-Type': 'application/json'
146        },
147        body: JSON.stringify(graphQLParams),
148        credentials: 'include',
149      }).then(function (response) {
150        return response.text();
151      }).then(function (responseBody) {
152        try {
153          return JSON.parse(responseBody);
154        } catch (error) {
155          return responseBody;
156        }
157      });
158    }
159
160    // When the query and variables string is edited, update the URL bar so
161    // that it can be easily shared.
162    function onEditQuery(newQuery) {
163      parameters.query = newQuery;
164      updateURL();
165    }
166
167    function onEditVariables(newVariables) {
168      parameters.variables = newVariables;
169      updateURL();
170    }
171
172    function onEditOperationName(newOperationName) {
173      parameters.operationName = newOperationName;
174      updateURL();
175    }
176
177    function updateURL() {
178      history.replaceState(null, null, locationQuery(parameters));
179    }
180
181    // Render <GraphiQL /> into the body.
182    ReactDOM.render(
183      React.createElement(GraphiQL, {
184        fetcher: graphQLFetcher,
185        onEditQuery: onEditQuery,
186        onEditVariables: onEditVariables,
187        onEditOperationName: onEditOperationName,
188        query: {{ .QueryString }},
189        response: {{ .ResultString }},
190        variables: {{ .VariablesString }},
191        operationName: {{ .OperationName }},
192      }),
193      document.body
194    );
195  </script>
196</body>
197</html>
198{{ end }}
199`