github.com/senomas/gqlgen@v0.17.11-0.20220626120754-9aee61b0716a/graphql/handler/transport/http_get.go (about)

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