github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/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  	}
    36  	raw.ReadTime.Start = graphql.Now()
    37  
    38  	if variables := r.URL.Query().Get("variables"); variables != "" {
    39  		if err := jsonDecode(strings.NewReader(variables), &raw.Variables); err != nil {
    40  			w.WriteHeader(http.StatusBadRequest)
    41  			writeJsonError(w, "variables could not be decoded")
    42  			return
    43  		}
    44  	}
    45  
    46  	if extensions := r.URL.Query().Get("extensions"); extensions != "" {
    47  		if err := jsonDecode(strings.NewReader(extensions), &raw.Extensions); err != nil {
    48  			w.WriteHeader(http.StatusBadRequest)
    49  			writeJsonError(w, "extensions could not be decoded")
    50  			return
    51  		}
    52  	}
    53  
    54  	raw.ReadTime.End = graphql.Now()
    55  
    56  	rc, err := exec.CreateOperationContext(r.Context(), raw)
    57  	if err != nil {
    58  		w.WriteHeader(statusFor(err))
    59  		resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
    60  		writeJson(w, resp)
    61  		return
    62  	}
    63  	op := rc.Doc.Operations.ForName(rc.OperationName)
    64  	if op.Operation != ast.Query {
    65  		w.WriteHeader(http.StatusNotAcceptable)
    66  		writeJsonError(w, "GET requests only allow query operations")
    67  		return
    68  	}
    69  
    70  	responses, ctx := exec.DispatchOperation(r.Context(), rc)
    71  	writeJson(w, responses(ctx))
    72  }
    73  
    74  func jsonDecode(r io.Reader, val interface{}) error {
    75  	dec := json.NewDecoder(r)
    76  	dec.UseNumber()
    77  	return dec.Decode(val)
    78  }
    79  
    80  func statusFor(errs gqlerror.List) int {
    81  	switch errcode.GetErrorKind(errs) {
    82  	case errcode.KindProtocol:
    83  		return http.StatusUnprocessableEntity
    84  	default:
    85  		return http.StatusOK
    86  	}
    87  }