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 }