From 59d710a2400be76b6cc5f2b89d5a7c8b079932ed Mon Sep 17 00:00:00 2001 From: David Koblas Date: Wed, 1 Aug 2018 14:07:17 -0400 Subject: [PATCH] Handle mutlipart/form-data --- README.md | 21 ++++ handler.go | 117 +++++++++++++++++-- handler_test.go | 249 ++++++++++++++++++++++++++++++++++++++++ request_options_test.go | 54 ++++----- 4 files changed, 405 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index eb08191..858e559 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,24 @@ h := handler.New(&handler.Config{ }) ``` +### Using Multipart Form Uploads + +This handler supports th +[GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec). +All file uploads will be made available as the following Scalar that you can add to your GraphQL schemas + +```go +var UploadScalar = graphql.NewScalar(graphql.ScalarConfig{ + Name: "Upload", + ParseValue: func(value interface{}) interface{} { + if v, ok := value.(*handler.MultipartFile); ok { + return v + } + return nil + }, +}) +``` + ### Details The handler will accept requests with @@ -70,6 +88,9 @@ depending on the provided `Content-Type` header. * **`application/graphql`**: The POST body will be parsed as GraphQL query string, which provides the `query` parameter. + * **`multipart/form-data`**: The POST body will be parsed as GraphQL + query string, which provides the `operations` parameter. + [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec) ### Examples - [golang-graphql-playground](https://github.com/graphql-go/playground) diff --git a/handler.go b/handler.go index ce2d700..b771b99 100644 --- a/handler.go +++ b/handler.go @@ -3,8 +3,10 @@ package handler import ( "encoding/json" "io/ioutil" + "mime/multipart" "net/http" "net/url" + "strconv" "strings" "github.com/graphql-go/graphql" @@ -13,17 +15,24 @@ import ( ) const ( - ContentTypeJSON = "application/json" - ContentTypeGraphQL = "application/graphql" - ContentTypeFormURLEncoded = "application/x-www-form-urlencoded" + ContentTypeJSON = "application/json" + ContentTypeGraphQL = "application/graphql" + ContentTypeFormURLEncoded = "application/x-www-form-urlencoded" + ContentTypeMultipartFormData = "multipart/form-data" ) +type MultipartFile struct { + File multipart.File + Header *multipart.FileHeader +} + type Handler struct { Schema *graphql.Schema pretty bool graphiql bool playground bool rootObjectFn RootObjectFn + maxMemory int64 } type RequestOptions struct { Query string `json:"query" url:"query" schema:"query"` @@ -57,7 +66,7 @@ func getFromForm(values url.Values) *RequestOptions { } // RequestOptions Parses a http.Request into GraphQL request options struct -func NewRequestOptions(r *http.Request) *RequestOptions { +func NewRequestOptions(r *http.Request, maxMemory int64) *RequestOptions { if reqOpt := getFromForm(r.URL.Query()); reqOpt != nil { return reqOpt } @@ -95,6 +104,89 @@ func NewRequestOptions(r *http.Request) *RequestOptions { return &RequestOptions{} + case ContentTypeMultipartFormData: + if err := r.ParseMultipartForm(maxMemory); err != nil { + // fmt.Printf("Parse Multipart Failed %v", err) + return &RequestOptions{} + } + + // @TODO handle array case... + + operationsParam := r.FormValue("operations") + var opts RequestOptions + if err := json.Unmarshal([]byte(operationsParam), &opts); err != nil { + // fmt.Printf("Parse Operations Failed %v", err) + return &RequestOptions{} + } + + mapParam := r.FormValue("map") + mapValues := make(map[string]([]string)) + if len(mapParam) != 0 { + if err := json.Unmarshal([]byte(mapParam), &mapValues); err != nil { + // fmt.Printf("Parse map Failed %v", err) + return &RequestOptions{} + } + } + + variables := opts + + for key, value := range mapValues { + for _, v := range value { + if file, header, err := r.FormFile(key); err == nil { + + // Now set the path in ther variables + var node interface{} = variables + + parts := strings.Split(v, ".") + last := parts[len(parts)-1] + + for _, vv := range parts[:len(parts)-1] { + // fmt.Printf("Doing vv=%s type=%T parts=%v\n", vv, node, parts) + switch node.(type) { + case RequestOptions: + if vv == "variables" { + node = opts.Variables + } else { + // panic("Invalid top level tag") + return &RequestOptions{} + } + case map[string]interface{}: + node = node.(map[string]interface{})[vv] + case []interface{}: + if idx, err := strconv.ParseInt(vv, 10, 64); err == nil { + node = node.([]interface{})[idx] + } else { + // panic("Unable to lookup index") + return &RequestOptions{} + } + default: + // panic(fmt.Errorf("Unknown type %T", node)) + return &RequestOptions{} + } + } + + data := &MultipartFile{File: file, Header: header} + + switch node.(type) { + case map[string]interface{}: + node.(map[string]interface{})[last] = data + case []interface{}: + if idx, err := strconv.ParseInt(last, 10, 64); err == nil { + node.([]interface{})[idx] = data + } else { + // panic("Unable to lookup index") + return &RequestOptions{} + } + default: + // panic(fmt.Errorf("Unknown last type %T", node)) + return &RequestOptions{} + } + } + } + } + + return &opts + case ContentTypeJSON: fallthrough default: @@ -119,7 +211,7 @@ func NewRequestOptions(r *http.Request) *RequestOptions { // user-provided context. func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { // get query - opts := NewRequestOptions(r) + opts := NewRequestOptions(r, h.maxMemory) // execute graphql query params := graphql.Params{ @@ -182,14 +274,15 @@ type Config struct { GraphiQL bool Playground bool RootObjectFn RootObjectFn + MaxMemory int64 } func NewConfig() *Config { return &Config{ - Schema: nil, - Pretty: true, - GraphiQL: true, - Playground: false, + Schema: nil, + Pretty: true, + GraphiQL: true, + MaxMemory: 0, } } @@ -201,11 +294,17 @@ func New(p *Config) *Handler { panic("undefined GraphQL schema") } + maxMemory := p.MaxMemory + if maxMemory == 0 { + maxMemory = 32 << 20 // 32MB + } + return &Handler{ Schema: p.Schema, pretty: p.Pretty, graphiql: p.GraphiQL, playground: p.Playground, rootObjectFn: p.RootObjectFn, + maxMemory: maxMemory, } } diff --git a/handler_test.go b/handler_test.go index 9a579fa..aa5b220 100644 --- a/handler_test.go +++ b/handler_test.go @@ -1,9 +1,12 @@ package handler_test import ( + "bytes" "encoding/json" "fmt" + "io" "io/ioutil" + "mime/multipart" "net/http" "net/http/httptest" "reflect" @@ -33,6 +36,7 @@ func decodeResponse(t *testing.T, recorder *httptest.ResponseRecorder) *graphql. } return &target } + func executeTest(t *testing.T, h *handler.Handler, req *http.Request) (*graphql.Result, *httptest.ResponseRecorder) { resp := httptest.NewRecorder() h.ServeHTTP(resp, req) @@ -40,6 +44,43 @@ func executeTest(t *testing.T, h *handler.Handler, req *http.Request) (*graphql. return result, resp } +func uploadTest(t *testing.T, mapData string) *http.Request { + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + + queryString := `{ + "query":"query HeroNameQuery { hero { name } }", + "variables":{"file":[null,null]} + }` + + writer.WriteField("operations", queryString) + if mapData != "" { + writer.WriteField("map", mapData) + + part1, _ := writer.CreateFormFile("0", "test1.txt") + if _, err := io.Copy(part1, strings.NewReader("How now brown cow")); err != nil { + t.Fatalf("unexpected copy writer fail %v", err) + } + part2, _ := writer.CreateFormFile("1", "test2.txt") + if _, err := io.Copy(part2, strings.NewReader("How now gold fish")); err != nil { + t.Fatalf("unexpected copy writer fail %v", err) + } + } + + err := writer.Close() + if err != nil { + t.Fatalf("unexpected writer fail %v", err) + } + + req, err := http.NewRequest("POST", "/graphql", body) + if err != nil { + t.Fatalf("unexpected NewRequest fail %v", err) + } + req.Header.Set("Content-Type", writer.FormDataContentType()) + + return req +} + func TestContextPropagated(t *testing.T) { myNameQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", @@ -196,3 +237,211 @@ func TestHandler_BasicQuery_WithRootObjFn(t *testing.T) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) } } + +func TestHandler_Post(t *testing.T) { + expected := &graphql.Result{ + Data: map[string]interface{}{ + "hero": map[string]interface{}{ + "name": "R2-D2", + }, + }, + } + queryString := `{"query":"query HeroNameQuery { hero { name } }"}` + + req, _ := http.NewRequest("POST", "/graphql", strings.NewReader(queryString)) + req.Header.Set("Content-Type", "application/json") + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) + } +} + +func TestHandler_Multipart_Basic(t *testing.T) { + expected := &graphql.Result{ + Data: map[string]interface{}{ + "hero": map[string]interface{}{ + "name": "R2-D2", + }, + }, + } + + req := uploadTest(t, "") + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) + } +} + +func TestHandler_Multipart_Basic_ErrNoOperation(t *testing.T) { + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + + err := writer.Close() + if err != nil { + t.Fatalf("unexpected writer fail %v", err) + } + + req, err := http.NewRequest("POST", "/graphql", body) + req.Header.Set("Content-Type", writer.FormDataContentType()) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response") + } +} + +func TestHandler_Multipart_Basic_ErrBadMap(t *testing.T) { + req := uploadTest(t, `{`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response") + } +} + +func TestHandler_Multipart_Basic_ErrBadMapRoot(t *testing.T) { + req := uploadTest(t, `{"0":["xxx.file"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response %+v", result) + } +} + +func TestHandler_Multipart_Basic_Upload(t *testing.T) { + expected := &graphql.Result{ + Data: map[string]interface{}{ + "hero": map[string]interface{}{ + "name": "R2-D2", + }, + }, + } + + req := uploadTest(t, `{"0":["variables.file"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) + } +} + +func TestHandler_Multipart_Basic_UploadSlice(t *testing.T) { + expected := &graphql.Result{ + Data: map[string]interface{}{ + "hero": map[string]interface{}{ + "name": "R2-D2", + }, + }, + } + + req := uploadTest(t, `{"0":["variables.file.0"],"1":["variables.file.1"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) + } +} + +func TestHandler_Multipart_Basic_BadSlice(t *testing.T) { + req := uploadTest(t, `{"0":["variables.file.x"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response %+v", result) + } +} + +func TestHandler_Multipart_Basic_BadSliceLast(t *testing.T) { + req := uploadTest(t, `{"0":["variables.file.0.test"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response %+v", result) + } +} + +func TestHandler_Multipart_Basic_BadSliceMiddle(t *testing.T) { + req := uploadTest(t, `{"0":["variables.file.x.test"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response %+v", result) + } +} + +func TestHandler_Multipart_Basic_BadMapPath(t *testing.T) { + req := uploadTest(t, `{"0":["variables.file.x.y.z.z.y"]}`) + + h := handler.New(&handler.Config{ + Schema: &testutil.StarWarsSchema, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if len(result.Errors) != 1 || result.Errors[0].Message != "Must provide an operation." { + t.Fatalf("unexpected response %+v", result) + } +} diff --git a/request_options_test.go b/request_options_test.go index aab7cc8..b84db46 100644 --- a/request_options_test.go +++ b/request_options_test.go @@ -19,7 +19,7 @@ func TestRequestOptions_GET_BasicQueryString(t *testing.T) { } req, _ := http.NewRequest("GET", fmt.Sprintf("/graphql?%v", queryString), nil) - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -31,7 +31,7 @@ func TestRequestOptions_GET_ContentTypeApplicationGraphQL(t *testing.T) { req, _ := http.NewRequest("GET", "/graphql", bytes.NewBuffer(body)) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -46,7 +46,7 @@ func TestRequestOptions_GET_ContentTypeApplicationJSON(t *testing.T) { req, _ := http.NewRequest("GET", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -60,7 +60,7 @@ func TestRequestOptions_GET_ContentTypeApplicationUrlEncoded(t *testing.T) { req, _ := http.NewRequest("GET", "/graphql", bytes.NewBufferString(data.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -75,7 +75,7 @@ func TestRequestOptions_POST_BasicQueryString_WithNoBody(t *testing.T) { } req, _ := http.NewRequest("POST", fmt.Sprintf("/graphql?%v", queryString), nil) - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -89,7 +89,7 @@ func TestRequestOptions_POST_ContentTypeApplicationGraphQL(t *testing.T) { req, _ := http.NewRequest("POST", "/graphql", bytes.NewBuffer(body)) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -103,7 +103,7 @@ func TestRequestOptions_POST_ContentTypeApplicationGraphQL_WithNonGraphQLQueryCo req, _ := http.NewRequest("POST", "/graphql", bytes.NewBuffer(body)) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -117,7 +117,7 @@ func TestRequestOptions_POST_ContentTypeApplicationGraphQL_EmptyBody(t *testing. req, _ := http.NewRequest("POST", "/graphql", bytes.NewBuffer(body)) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -128,7 +128,7 @@ func TestRequestOptions_POST_ContentTypeApplicationGraphQL_NilBody(t *testing.T) req, _ := http.NewRequest("POST", "/graphql", nil) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -146,7 +146,7 @@ func TestRequestOptions_POST_ContentTypeApplicationJSON(t *testing.T) { req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -166,7 +166,7 @@ func TestRequestOptions_GET_WithVariablesAsObject(t *testing.T) { } req, _ := http.NewRequest("GET", fmt.Sprintf("/graphql?%v", queryString), nil) - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -189,7 +189,7 @@ func TestRequestOptions_POST_ContentTypeApplicationJSON_WithVariablesAsObject(t req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -211,7 +211,7 @@ func TestRequestOptions_POST_ContentTypeApplicationJSON_WithVariablesAsString(t req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -223,7 +223,7 @@ func TestRequestOptions_POST_ContentTypeApplicationJSON_WithInvalidJSON(t *testi req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -234,7 +234,7 @@ func TestRequestOptions_POST_ContentTypeApplicationJSON_WithNilBody(t *testing.T req, _ := http.NewRequest("POST", "/graphql", nil) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -252,7 +252,7 @@ func TestRequestOptions_POST_ContentTypeApplicationUrlEncoded(t *testing.T) { req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(data.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -265,7 +265,7 @@ func TestRequestOptions_POST_ContentTypeApplicationUrlEncoded_WithInvalidData(t req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(data)) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -277,7 +277,7 @@ func TestRequestOptions_POST_ContentTypeApplicationUrlEncoded_WithNilBody(t *tes req, _ := http.NewRequest("POST", "/graphql", nil) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -292,7 +292,7 @@ func TestRequestOptions_PUT_BasicQueryString(t *testing.T) { } req, _ := http.NewRequest("PUT", fmt.Sprintf("/graphql?%v", queryString), nil) - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -304,7 +304,7 @@ func TestRequestOptions_PUT_ContentTypeApplicationGraphQL(t *testing.T) { req, _ := http.NewRequest("PUT", "/graphql", bytes.NewBuffer(body)) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -319,7 +319,7 @@ func TestRequestOptions_PUT_ContentTypeApplicationJSON(t *testing.T) { req, _ := http.NewRequest("PUT", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -333,7 +333,7 @@ func TestRequestOptions_PUT_ContentTypeApplicationUrlEncoded(t *testing.T) { req, _ := http.NewRequest("PUT", "/graphql", bytes.NewBufferString(data.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -348,7 +348,7 @@ func TestRequestOptions_DELETE_BasicQueryString(t *testing.T) { } req, _ := http.NewRequest("DELETE", fmt.Sprintf("/graphql?%v", queryString), nil) - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -360,7 +360,7 @@ func TestRequestOptions_DELETE_ContentTypeApplicationGraphQL(t *testing.T) { req, _ := http.NewRequest("DELETE", "/graphql", bytes.NewBuffer(body)) req.Header.Add("Content-Type", "application/graphql") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -375,7 +375,7 @@ func TestRequestOptions_DELETE_ContentTypeApplicationJSON(t *testing.T) { req, _ := http.NewRequest("DELETE", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/json") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -389,7 +389,7 @@ func TestRequestOptions_DELETE_ContentTypeApplicationUrlEncoded(t *testing.T) { req, _ := http.NewRequest("DELETE", "/graphql", bytes.NewBufferString(data.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) @@ -402,7 +402,7 @@ func TestRequestOptions_POST_UnsupportedContentType(t *testing.T) { req, _ := http.NewRequest("POST", "/graphql", bytes.NewBufferString(body)) req.Header.Add("Content-Type", "application/xml") - result := NewRequestOptions(req) + result := NewRequestOptions(req, 0) if !reflect.DeepEqual(result, expected) { t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result))