diff options
Diffstat (limited to 'vendor/github.com/graphql-go/handler')
-rw-r--r-- | vendor/github.com/graphql-go/handler/.gitignore | 25 | ||||
-rw-r--r-- | vendor/github.com/graphql-go/handler/.travis.yml | 12 | ||||
-rw-r--r-- | vendor/github.com/graphql-go/handler/LICENSE | 22 | ||||
-rw-r--r-- | vendor/github.com/graphql-go/handler/README.md | 79 | ||||
-rw-r--r-- | vendor/github.com/graphql-go/handler/graphiql.go | 199 | ||||
-rw-r--r-- | vendor/github.com/graphql-go/handler/handler.go | 189 |
6 files changed, 526 insertions, 0 deletions
diff --git a/vendor/github.com/graphql-go/handler/.gitignore b/vendor/github.com/graphql-go/handler/.gitignore new file mode 100644 index 00000000..3a709f36 --- /dev/null +++ b/vendor/github.com/graphql-go/handler/.gitignore @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +*.swp diff --git a/vendor/github.com/graphql-go/handler/.travis.yml b/vendor/github.com/graphql-go/handler/.travis.yml new file mode 100644 index 00000000..3fee687b --- /dev/null +++ b/vendor/github.com/graphql-go/handler/.travis.yml @@ -0,0 +1,12 @@ +language: go + +go: + - 1.x + - tip + +before_install: + - go get github.com/axw/gocov/gocov + - go get github.com/mattn/goveralls + +script: + - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/graphql-go/handler/LICENSE b/vendor/github.com/graphql-go/handler/LICENSE new file mode 100644 index 00000000..4bcca848 --- /dev/null +++ b/vendor/github.com/graphql-go/handler/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hafiz Ismail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/graphql-go/handler/README.md b/vendor/github.com/graphql-go/handler/README.md new file mode 100644 index 00000000..a6986c5e --- /dev/null +++ b/vendor/github.com/graphql-go/handler/README.md @@ -0,0 +1,79 @@ +# graphql-go-handler [![Build Status](https://travis-ci.org/graphql-go/handler.svg)](https://travis-ci.org/graphql-go/handler) [![GoDoc](https://godoc.org/graphql-go/handler?status.svg)](https://godoc.org/github.com/graphql-go/handler) [![Coverage Status](https://coveralls.io/repos/graphql-go/handler/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-go/handler?branch=master) [![Join the chat at https://gitter.im/graphql-go/graphql](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/graphql-go/graphql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Golang HTTP.Handler for [graphl-go](https://github.com/graphql-go/graphql) + +### Notes: +This is based on alpha version of `graphql-go` and `graphql-relay-go`. +Be sure to watch both repositories for latest changes. + +### Usage + +```go +package main + +import ( + "net/http" + "github.com/graphql-go/handler" +) + +func main() { + + // define GraphQL schema using relay library helpers + schema := graphql.NewSchema(...) + + h := handler.New(&handler.Config{ + Schema: &schema, + Pretty: true, + GraphiQL: true, + }) + + // serve HTTP + http.Handle("/graphql", h) + http.ListenAndServe(":8080", nil) +} +``` + +### Details + +The handler will accept requests with +the parameters: + + * **`query`**: A string GraphQL document to be executed. + + * **`variables`**: The runtime values to use for any GraphQL query variables + as a JSON object. + + * **`operationName`**: If the provided `query` contains multiple named + operations, this specifies which operation should be executed. If not + provided, an 400 error will be returned if the `query` contains multiple + named operations. + +GraphQL will first look for each parameter in the URL's query-string: + +``` +/graphql?query=query+getUser($id:ID){user(id:$id){name}}&variables={"id":"4"} +``` + +If not found in the query-string, it will look in the POST request body. +The `handler` will interpret it +depending on the provided `Content-Type` header. + + * **`application/json`**: the POST body will be parsed as a JSON + object of parameters. + + * **`application/x-www-form-urlencoded`**: this POST body will be + parsed as a url-encoded string of key-value pairs. + + * **`application/graphql`**: The POST body will be parsed as GraphQL + query string, which provides the `query` parameter. + + +### Examples +- [golang-graphql-playground](https://github.com/graphql-go/playground) +- [golang-relay-starter-kit](https://github.com/sogko/golang-relay-starter-kit) +- [todomvc-relay-go](https://github.com/sogko/todomvc-relay-go) + +### Test +```bash +$ go get github.com/graphql-go/handler +$ go build && go test ./... diff --git a/vendor/github.com/graphql-go/handler/graphiql.go b/vendor/github.com/graphql-go/handler/graphiql.go new file mode 100644 index 00000000..ace949b4 --- /dev/null +++ b/vendor/github.com/graphql-go/handler/graphiql.go @@ -0,0 +1,199 @@ +package handler + +import ( + "encoding/json" + "html/template" + "net/http" + + "github.com/graphql-go/graphql" +) + +// page is the page data structure of the rendered GraphiQL page +type graphiqlPage struct { + GraphiqlVersion string + QueryString string + ResultString string + VariablesString string + OperationName string +} + +// renderGraphiQL renders the GraphiQL GUI +func renderGraphiQL(w http.ResponseWriter, params graphql.Params) { + t := template.New("GraphiQL") + t, err := t.Parse(graphiqlTemplate) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Create variables string + vars, err := json.MarshalIndent(params.VariableValues, "", " ") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + varsString := string(vars) + if varsString == "null" { + varsString = "" + } + + // Create result string + var resString string + if params.RequestString == "" { + resString = "" + } else { + result, err := json.MarshalIndent(graphql.Do(params), "", " ") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + resString = string(result) + } + + p := graphiqlPage{ + GraphiqlVersion: graphiqlVersion, + QueryString: params.RequestString, + ResultString: resString, + VariablesString: varsString, + OperationName: params.OperationName, + } + + err = t.ExecuteTemplate(w, "index", p) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return +} + +// graphiqlVersion is the current version of GraphiQL +const graphiqlVersion = "0.11.3" + +// tmpl is the page template to render GraphiQL +const graphiqlTemplate = ` +{{ define "index" }} +<!-- +The request to this GraphQL server provided the header "Accept: text/html" +and as a result has been presented GraphiQL - an in-browser IDE for +exploring GraphQL. + +If you wish to receive JSON, provide the header "Accept: application/json" or +add "&raw" to the end of the URL within a browser. +--> +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8" /> + <title>GraphiQL</title> + <meta name="robots" content="noindex" /> + <style> + html, body { + height: 100%; + margin: 0; + overflow: hidden; + width: 100%; + } + </style> + <link href="//cdn.jsdelivr.net/npm/graphiql@{{ .GraphiqlVersion }}/graphiql.css" rel="stylesheet" /> + <script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script> + <script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script> + <script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script> + <script src="//cdn.jsdelivr.net/npm/graphiql@{{ .GraphiqlVersion }}/graphiql.min.js"></script> +</head> +<body> + <script> + // Collect the URL parameters + var parameters = {}; + window.location.search.substr(1).split('&').forEach(function (entry) { + var eq = entry.indexOf('='); + if (eq >= 0) { + parameters[decodeURIComponent(entry.slice(0, eq))] = + decodeURIComponent(entry.slice(eq + 1)); + } + }); + + // Produce a Location query string from a parameter object. + function locationQuery(params) { + return '?' + Object.keys(params).filter(function (key) { + return Boolean(params[key]); + }).map(function (key) { + return encodeURIComponent(key) + '=' + + encodeURIComponent(params[key]); + }).join('&'); + } + + // Derive a fetch URL from the current URL, sans the GraphQL parameters. + var graphqlParamNames = { + query: true, + variables: true, + operationName: true + }; + + var otherParams = {}; + for (var k in parameters) { + if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) { + otherParams[k] = parameters[k]; + } + } + var fetchURL = locationQuery(otherParams); + + // Defines a GraphQL fetcher using the fetch API. + function graphQLFetcher(graphQLParams) { + return fetch(fetchURL, { + method: 'post', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(graphQLParams), + credentials: 'include', + }).then(function (response) { + return response.text(); + }).then(function (responseBody) { + try { + return JSON.parse(responseBody); + } catch (error) { + return responseBody; + } + }); + } + + // When the query and variables string is edited, update the URL bar so + // that it can be easily shared. + function onEditQuery(newQuery) { + parameters.query = newQuery; + updateURL(); + } + + function onEditVariables(newVariables) { + parameters.variables = newVariables; + updateURL(); + } + + function onEditOperationName(newOperationName) { + parameters.operationName = newOperationName; + updateURL(); + } + + function updateURL() { + history.replaceState(null, null, locationQuery(parameters)); + } + + // Render <GraphiQL /> into the body. + ReactDOM.render( + React.createElement(GraphiQL, { + fetcher: graphQLFetcher, + onEditQuery: onEditQuery, + onEditVariables: onEditVariables, + onEditOperationName: onEditOperationName, + query: {{ .QueryString }}, + response: {{ .ResultString }}, + variables: {{ .VariablesString }}, + operationName: {{ .OperationName }}, + }), + document.body + ); + </script> +</body> +</html> +{{ end }} +` diff --git a/vendor/github.com/graphql-go/handler/handler.go b/vendor/github.com/graphql-go/handler/handler.go new file mode 100644 index 00000000..cfcb1ca9 --- /dev/null +++ b/vendor/github.com/graphql-go/handler/handler.go @@ -0,0 +1,189 @@ +package handler + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/graphql-go/graphql" + + "context" +) + +const ( + ContentTypeJSON = "application/json" + ContentTypeGraphQL = "application/graphql" + ContentTypeFormURLEncoded = "application/x-www-form-urlencoded" +) + +type Handler struct { + Schema *graphql.Schema + pretty bool + graphiql bool +} +type RequestOptions struct { + Query string `json:"query" url:"query" schema:"query"` + Variables map[string]interface{} `json:"variables" url:"variables" schema:"variables"` + OperationName string `json:"operationName" url:"operationName" schema:"operationName"` +} + +// a workaround for getting`variables` as a JSON string +type requestOptionsCompatibility struct { + Query string `json:"query" url:"query" schema:"query"` + Variables string `json:"variables" url:"variables" schema:"variables"` + OperationName string `json:"operationName" url:"operationName" schema:"operationName"` +} + +func getFromForm(values url.Values) *RequestOptions { + query := values.Get("query") + if query != "" { + // get variables map + variables := make(map[string]interface{}, len(values)) + variablesStr := values.Get("variables") + json.Unmarshal([]byte(variablesStr), &variables) + + return &RequestOptions{ + Query: query, + Variables: variables, + OperationName: values.Get("operationName"), + } + } + + return nil +} + +// RequestOptions Parses a http.Request into GraphQL request options struct +func NewRequestOptions(r *http.Request) *RequestOptions { + if reqOpt := getFromForm(r.URL.Query()); reqOpt != nil { + return reqOpt + } + + if r.Method != "POST" { + return &RequestOptions{} + } + + if r.Body == nil { + return &RequestOptions{} + } + + // TODO: improve Content-Type handling + contentTypeStr := r.Header.Get("Content-Type") + contentTypeTokens := strings.Split(contentTypeStr, ";") + contentType := contentTypeTokens[0] + + switch contentType { + case ContentTypeGraphQL: + body, err := ioutil.ReadAll(r.Body) + if err != nil { + return &RequestOptions{} + } + return &RequestOptions{ + Query: string(body), + } + case ContentTypeFormURLEncoded: + if err := r.ParseForm(); err != nil { + return &RequestOptions{} + } + + if reqOpt := getFromForm(r.PostForm); reqOpt != nil { + return reqOpt + } + + return &RequestOptions{} + + case ContentTypeJSON: + fallthrough + default: + var opts RequestOptions + body, err := ioutil.ReadAll(r.Body) + if err != nil { + return &opts + } + err = json.Unmarshal(body, &opts) + if err != nil { + // Probably `variables` was sent as a string instead of an object. + // So, we try to be polite and try to parse that as a JSON string + var optsCompatible requestOptionsCompatibility + json.Unmarshal(body, &optsCompatible) + json.Unmarshal([]byte(optsCompatible.Variables), &opts.Variables) + } + return &opts + } +} + +// ContextHandler provides an entrypoint into executing graphQL queries with a +// user-provided context. +func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { + // get query + opts := NewRequestOptions(r) + + // execute graphql query + params := graphql.Params{ + Schema: *h.Schema, + RequestString: opts.Query, + VariableValues: opts.Variables, + OperationName: opts.OperationName, + Context: ctx, + } + result := graphql.Do(params) + + if h.graphiql { + acceptHeader := r.Header.Get("Accept") + _, raw := r.URL.Query()["raw"] + if !raw && !strings.Contains(acceptHeader, "application/json") && strings.Contains(acceptHeader, "text/html") { + renderGraphiQL(w, params) + return + } + } + + // use proper JSON Header + w.Header().Add("Content-Type", "application/json; charset=utf-8") + + if h.pretty { + w.WriteHeader(http.StatusOK) + buff, _ := json.MarshalIndent(result, "", "\t") + + w.Write(buff) + } else { + w.WriteHeader(http.StatusOK) + buff, _ := json.Marshal(result) + + w.Write(buff) + } +} + +// ServeHTTP provides an entrypoint into executing graphQL queries. +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.ContextHandler(r.Context(), w, r) +} + +type Config struct { + Schema *graphql.Schema + Pretty bool + GraphiQL bool +} + +func NewConfig() *Config { + return &Config{ + Schema: nil, + Pretty: true, + GraphiQL: true, + } +} + +func New(p *Config) *Handler { + if p == nil { + p = NewConfig() + } + if p.Schema == nil { + panic("undefined GraphQL schema") + } + + return &Handler{ + Schema: p.Schema, + pretty: p.Pretty, + graphiql: p.GraphiQL, + } +} |