github.com/99designs/gqlgen@v0.17.45/graphql/handler/transport/http_form_urlencoded.go (about) 1 package transport 2 3 import ( 4 "io" 5 "mime" 6 "net/http" 7 "net/url" 8 "strings" 9 10 "github.com/vektah/gqlparser/v2/gqlerror" 11 12 "github.com/99designs/gqlgen/graphql" 13 ) 14 15 // FORM implements the application/x-www-form-urlencoded side of the default HTTP transport 16 type UrlEncodedForm struct { 17 // Map of all headers that are added to graphql response. If not 18 // set, only one header: Content-Type: application/json will be set. 19 ResponseHeaders map[string][]string 20 } 21 22 var _ graphql.Transport = UrlEncodedForm{} 23 24 func (h UrlEncodedForm) Supports(r *http.Request) bool { 25 if r.Header.Get("Upgrade") != "" { 26 return false 27 } 28 29 mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) 30 if err != nil { 31 return false 32 } 33 34 return r.Method == "POST" && mediaType == "application/x-www-form-urlencoded" 35 } 36 37 func (h UrlEncodedForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { 38 ctx := r.Context() 39 writeHeaders(w, h.ResponseHeaders) 40 params := &graphql.RawParams{} 41 start := graphql.Now() 42 params.Headers = r.Header 43 params.ReadTime = graphql.TraceTiming{ 44 Start: start, 45 End: graphql.Now(), 46 } 47 48 bodyString, err := getRequestBody(r) 49 if err != nil { 50 w.WriteHeader(http.StatusBadRequest) 51 gqlErr := gqlerror.Errorf("could not get form body: %+v", err) 52 resp := exec.DispatchError(ctx, gqlerror.List{gqlErr}) 53 writeJson(w, resp) 54 return 55 } 56 57 params, err = h.parseBody(bodyString) 58 if err != nil { 59 w.WriteHeader(http.StatusUnprocessableEntity) 60 gqlErr := gqlerror.Errorf("could not cleanup body: %+v", err) 61 resp := exec.DispatchError(ctx, gqlerror.List{gqlErr}) 62 writeJson(w, resp) 63 return 64 } 65 66 rc, OpErr := exec.CreateOperationContext(ctx, params) 67 if OpErr != nil { 68 w.WriteHeader(statusFor(OpErr)) 69 resp := exec.DispatchError(graphql.WithOperationContext(ctx, rc), OpErr) 70 writeJson(w, resp) 71 return 72 } 73 74 var responses graphql.ResponseHandler 75 responses, ctx = exec.DispatchOperation(ctx, rc) 76 writeJson(w, responses(ctx)) 77 } 78 79 func (h UrlEncodedForm) parseBody(bodyString string) (*graphql.RawParams, error) { 80 switch { 81 case strings.Contains(bodyString, "\"query\":"): 82 // body is json 83 return h.parseJson(bodyString) 84 case strings.HasPrefix(bodyString, "query=%7B"): 85 // body is urlencoded 86 return h.parseEncoded(bodyString) 87 default: 88 // body is plain text 89 params := &graphql.RawParams{} 90 params.Query = strings.TrimPrefix(bodyString, "query=") 91 92 return params, nil 93 } 94 } 95 96 func (h UrlEncodedForm) parseEncoded(bodyString string) (*graphql.RawParams, error) { 97 params := &graphql.RawParams{} 98 99 query, err := url.QueryUnescape(bodyString) 100 if err != nil { 101 return nil, err 102 } 103 104 params.Query = strings.TrimPrefix(query, "query=") 105 106 return params, nil 107 } 108 109 func (h UrlEncodedForm) parseJson(bodyString string) (*graphql.RawParams, error) { 110 params := &graphql.RawParams{} 111 bodyReader := io.NopCloser(strings.NewReader(bodyString)) 112 113 err := jsonDecode(bodyReader, ¶ms) 114 if err != nil { 115 return nil, err 116 } 117 118 return params, nil 119 }