...

Source file src/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go

Documentation: github.com/99designs/gqlgen/graphql/handler/transport

     1  package transport
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"net/http"
     7  	"net/url"
     8  	"strings"
     9  
    10  	"github.com/vektah/gqlparser/v2/ast"
    11  	"github.com/vektah/gqlparser/v2/gqlerror"
    12  
    13  	"github.com/99designs/gqlgen/graphql"
    14  	"github.com/99designs/gqlgen/graphql/errcode"
    15  )
    16  
    17  // GET implements the GET side of the default HTTP transport
    18  // defined in https://github.com/APIs-guru/graphql-over-http#get
    19  type GET struct {
    20  	// Map of all headers that are added to graphql response. If not
    21  	// set, only one header: Content-Type: application/json will be set.
    22  	ResponseHeaders map[string][]string
    23  }
    24  
    25  var _ graphql.Transport = GET{}
    26  
    27  func (h GET) Supports(r *http.Request) bool {
    28  	if r.Header.Get("Upgrade") != "" {
    29  		return false
    30  	}
    31  
    32  	return r.Method == "GET"
    33  }
    34  
    35  func (h GET) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
    36  	query, err := url.ParseQuery(r.URL.RawQuery)
    37  	if err != nil {
    38  		w.WriteHeader(http.StatusBadRequest)
    39  		writeJsonError(w, err.Error())
    40  		return
    41  	}
    42  	writeHeaders(w, h.ResponseHeaders)
    43  
    44  	raw := &graphql.RawParams{
    45  		Query:         query.Get("query"),
    46  		OperationName: query.Get("operationName"),
    47  		Headers:       r.Header,
    48  	}
    49  	raw.ReadTime.Start = graphql.Now()
    50  
    51  	if variables := query.Get("variables"); variables != "" {
    52  		if err := jsonDecode(strings.NewReader(variables), &raw.Variables); err != nil {
    53  			w.WriteHeader(http.StatusBadRequest)
    54  			writeJsonError(w, "variables could not be decoded")
    55  			return
    56  		}
    57  	}
    58  
    59  	if extensions := query.Get("extensions"); extensions != "" {
    60  		if err := jsonDecode(strings.NewReader(extensions), &raw.Extensions); err != nil {
    61  			w.WriteHeader(http.StatusBadRequest)
    62  			writeJsonError(w, "extensions could not be decoded")
    63  			return
    64  		}
    65  	}
    66  
    67  	raw.ReadTime.End = graphql.Now()
    68  
    69  	rc, gqlError := exec.CreateOperationContext(r.Context(), raw)
    70  	if gqlError != nil {
    71  		w.WriteHeader(statusFor(gqlError))
    72  		resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), gqlError)
    73  		writeJson(w, resp)
    74  		return
    75  	}
    76  	op := rc.Doc.Operations.ForName(rc.OperationName)
    77  	if op.Operation != ast.Query {
    78  		w.WriteHeader(http.StatusNotAcceptable)
    79  		writeJsonError(w, "GET requests only allow query operations")
    80  		return
    81  	}
    82  
    83  	responses, ctx := exec.DispatchOperation(r.Context(), rc)
    84  	writeJson(w, responses(ctx))
    85  }
    86  
    87  func jsonDecode(r io.Reader, val interface{}) error {
    88  	dec := json.NewDecoder(r)
    89  	dec.UseNumber()
    90  	return dec.Decode(val)
    91  }
    92  
    93  func statusFor(errs gqlerror.List) int {
    94  	switch errcode.GetErrorKind(errs) {
    95  	case errcode.KindProtocol:
    96  		return http.StatusUnprocessableEntity
    97  	default:
    98  		return http.StatusOK
    99  	}
   100  }
   101  

View as plain text