diff --git a/graphql/handler/transport/headers_test.go b/graphql/handler/transport/headers_test.go index 5e8160861a2..c599c929359 100644 --- a/graphql/handler/transport/headers_test.go +++ b/graphql/handler/transport/headers_test.go @@ -21,7 +21,7 @@ func TestHeadersWithPOST(t *testing.T) { h := testserver.New() h.AddTransport(transport.POST{}) - resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }"}`) + resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }"}`, "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, 1, len(resp.Header())) assert.Equal(t, "application/json", resp.Header().Get("Content-Type")) @@ -36,7 +36,7 @@ func TestHeadersWithPOST(t *testing.T) { h := testserver.New() h.AddTransport(transport.POST{ResponseHeaders: headers}) - resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }"}`) + resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }"}`, "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, 2, len(resp.Header())) assert.Equal(t, "application/json; charset: utf8", resp.Header().Get("Content-Type")) @@ -50,7 +50,7 @@ func TestHeadersWithGET(t *testing.T) { h := testserver.New() h.AddTransport(transport.GET{}) - resp := doRequest(h, "GET", "/graphql?query={name}", "") + resp := doRequest(h, "GET", "/graphql?query={name}", "", "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, 1, len(resp.Header())) assert.Equal(t, "application/json", resp.Header().Get("Content-Type")) @@ -65,7 +65,7 @@ func TestHeadersWithGET(t *testing.T) { h := testserver.New() h.AddTransport(transport.GET{ResponseHeaders: headers}) - resp := doRequest(h, "GET", "/graphql?query={name}", "") + resp := doRequest(h, "GET", "/graphql?query={name}", "", "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, 2, len(resp.Header())) assert.Equal(t, "application/json; charset: utf8", resp.Header().Get("Content-Type")) @@ -73,6 +73,34 @@ func TestHeadersWithGET(t *testing.T) { }) } +func TestHeadersWithGRAPHQL(t *testing.T) { + t.Run("Headers not set", func(t *testing.T) { + h := testserver.New() + h.AddTransport(transport.GRAPHQL{}) + + resp := doRequest(h, "POST", "/graphql", `{ name }`, "application/graphql") + assert.Equal(t, http.StatusOK, resp.Code) + assert.Equal(t, 1, len(resp.Header())) + assert.Equal(t, "application/json", resp.Header().Get("Content-Type")) + }) + + t.Run("Headers set", func(t *testing.T) { + headers := map[string][]string{ + "Content-Type": {"application/json; charset: utf8"}, + "Other-Header": {"dummy-get-qraphql"}, + } + + h := testserver.New() + h.AddTransport(transport.GRAPHQL{ResponseHeaders: headers}) + + resp := doRequest(h, "POST", "/graphql", `{ name }`, "application/graphql") + assert.Equal(t, http.StatusOK, resp.Code) + assert.Equal(t, 2, len(resp.Header())) + assert.Equal(t, "application/json; charset: utf8", resp.Header().Get("Content-Type")) + assert.Equal(t, "dummy-get-qraphql", resp.Header().Get("Other-Header")) + }) +} + func TestHeadersWithMULTIPART(t *testing.T) { t.Run("Headers not set", func(t *testing.T) { es := &graphql.ExecutableSchemaMock{ diff --git a/graphql/handler/transport/http_get_test.go b/graphql/handler/transport/http_get_test.go index 307b2b90357..5e46d231855 100644 --- a/graphql/handler/transport/http_get_test.go +++ b/graphql/handler/transport/http_get_test.go @@ -14,36 +14,36 @@ func TestGET(t *testing.T) { h.AddTransport(transport.GET{}) t.Run("success", func(t *testing.T) { - resp := doRequest(h, "GET", "/graphql?query={name}", ``) + resp := doRequest(h, "GET", "/graphql?query={name}", ``, "application/json") assert.Equal(t, http.StatusOK, resp.Code, resp.Body.String()) assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) }) t.Run("has json content-type header", func(t *testing.T) { - resp := doRequest(h, "GET", "/graphql?query={name}", ``) + resp := doRequest(h, "GET", "/graphql?query={name}", ``, "application/json") assert.Equal(t, "application/json", resp.Header().Get("Content-Type")) }) t.Run("decode failure", func(t *testing.T) { - resp := doRequest(h, "GET", "/graphql?query={name}&variables=notjson", "") + resp := doRequest(h, "GET", "/graphql?query={name}&variables=notjson", "", "application/json") assert.Equal(t, http.StatusBadRequest, resp.Code, resp.Body.String()) assert.Equal(t, `{"errors":[{"message":"variables could not be decoded"}],"data":null}`, resp.Body.String()) }) t.Run("invalid variable", func(t *testing.T) { - resp := doRequest(h, "GET", `/graphql?query=query($id:Int!){find(id:$id)}&variables={"id":false}`, "") + resp := doRequest(h, "GET", `/graphql?query=query($id:Int!){find(id:$id)}&variables={"id":false}`, "", "application/json") assert.Equal(t, http.StatusUnprocessableEntity, resp.Code, resp.Body.String()) assert.Equal(t, `{"errors":[{"message":"cannot use bool as Int","path":["variable","id"],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"data":null}`, resp.Body.String()) }) t.Run("parse failure", func(t *testing.T) { - resp := doRequest(h, "GET", "/graphql?query=!", "") + resp := doRequest(h, "GET", "/graphql?query=!", "", "application/json") assert.Equal(t, http.StatusUnprocessableEntity, resp.Code, resp.Body.String()) assert.Equal(t, `{"errors":[{"message":"Unexpected !","locations":[{"line":1,"column":1}],"extensions":{"code":"GRAPHQL_PARSE_FAILED"}}],"data":null}`, resp.Body.String()) }) t.Run("no mutations", func(t *testing.T) { - resp := doRequest(h, "GET", "/graphql?query=mutation{name}", "") + resp := doRequest(h, "GET", "/graphql?query=mutation{name}", "", "application/json") assert.Equal(t, http.StatusNotAcceptable, resp.Code, resp.Body.String()) assert.Equal(t, `{"errors":[{"message":"GET requests only allow query operations"}],"data":null}`, resp.Body.String()) }) diff --git a/graphql/handler/transport/http_post_test.go b/graphql/handler/transport/http_post_test.go index b104118e6fd..a26ba12912e 100644 --- a/graphql/handler/transport/http_post_test.go +++ b/graphql/handler/transport/http_post_test.go @@ -17,41 +17,41 @@ func TestPOST(t *testing.T) { h.AddTransport(transport.POST{}) t.Run("success", func(t *testing.T) { - resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }"}`) + resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }"}`, "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) }) t.Run("decode failure", func(t *testing.T) { - resp := doRequest(h, "POST", "/graphql", "notjson") + resp := doRequest(h, "POST", "/graphql", "notjson", "application/json") assert.Equal(t, http.StatusBadRequest, resp.Code, resp.Body.String()) assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") assert.Equal(t, `{"errors":[{"message":"json request body could not be decoded: invalid character 'o' in literal null (expecting 'u') body:notjson"}],"data":null}`, resp.Body.String()) }) t.Run("parse failure", func(t *testing.T) { - resp := doRequest(h, "POST", "/graphql", `{"query": "!"}`) + resp := doRequest(h, "POST", "/graphql", `{"query": "!"}`, "application/json") assert.Equal(t, http.StatusUnprocessableEntity, resp.Code, resp.Body.String()) assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") assert.Equal(t, `{"errors":[{"message":"Unexpected !","locations":[{"line":1,"column":1}],"extensions":{"code":"GRAPHQL_PARSE_FAILED"}}],"data":null}`, resp.Body.String()) }) t.Run("validation failure", func(t *testing.T) { - resp := doRequest(h, "POST", "/graphql", `{"query": "{ title }"}`) + resp := doRequest(h, "POST", "/graphql", `{"query": "{ title }"}`, "application/json") assert.Equal(t, http.StatusUnprocessableEntity, resp.Code, resp.Body.String()) assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") assert.Equal(t, `{"errors":[{"message":"Cannot query field \"title\" on type \"Query\".","locations":[{"line":1,"column":3}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"data":null}`, resp.Body.String()) }) t.Run("invalid variable", func(t *testing.T) { - resp := doRequest(h, "POST", "/graphql", `{"query": "query($id:Int!){find(id:$id)}","variables":{"id":false}}`) + resp := doRequest(h, "POST", "/graphql", `{"query": "query($id:Int!){find(id:$id)}","variables":{"id":false}}`, "application/json") assert.Equal(t, http.StatusUnprocessableEntity, resp.Code, resp.Body.String()) assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") assert.Equal(t, `{"errors":[{"message":"cannot use bool as Int","path":["variable","id"],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"data":null}`, resp.Body.String()) }) t.Run("execution failure", func(t *testing.T) { - resp := doRequest(h, "POST", "/graphql", `{"query": "mutation { name }"}`) + resp := doRequest(h, "POST", "/graphql", `{"query": "mutation { name }"}`, "application/json") assert.Equal(t, http.StatusOK, resp.Code, resp.Body.String()) assert.Equal(t, resp.Header().Get("Content-Type"), "application/json") assert.Equal(t, `{"errors":[{"message":"mutations are not supported"}],"data":null}`, resp.Body.String()) @@ -85,10 +85,6 @@ func TestPOST(t *testing.T) { invalidContentTypes := []string{ "", "text/plain", - - // These content types are currently not supported, but they are supported by other GraphQL servers, like express-graphql. - "application/x-www-form-urlencoded", - "application/graphql", } for _, tc := range invalidContentTypes { @@ -101,9 +97,9 @@ func TestPOST(t *testing.T) { }) } -func doRequest(handler http.Handler, method string, target string, body string) *httptest.ResponseRecorder { +func doRequest(handler http.Handler, method string, target string, body string, contentType string) *httptest.ResponseRecorder { r := httptest.NewRequest(method, target, strings.NewReader(body)) - r.Header.Set("Content-Type", "application/json") + r.Header.Set("Content-Type", contentType) w := httptest.NewRecorder() handler.ServeHTTP(w, r) diff --git a/graphql/handler/transport/options_test.go b/graphql/handler/transport/options_test.go index fee62752126..f0812c58fb4 100644 --- a/graphql/handler/transport/options_test.go +++ b/graphql/handler/transport/options_test.go @@ -14,7 +14,7 @@ func TestOptions(t *testing.T) { t.Run("responds to options requests with default methods", func(t *testing.T) { h := testserver.New() h.AddTransport(transport.Options{}) - resp := doRequest(h, "OPTIONS", "/graphql?query={me{name}}", ``) + resp := doRequest(h, "OPTIONS", "/graphql?query={me{name}}", ``, "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, "OPTIONS, GET, POST", resp.Header().Get("Allow")) }) @@ -24,7 +24,7 @@ func TestOptions(t *testing.T) { h.AddTransport(transport.Options{ AllowedMethods: []string{http.MethodOptions, http.MethodPost, http.MethodHead}, }) - resp := doRequest(h, "OPTIONS", "/graphql?query={me{name}}", ``) + resp := doRequest(h, "OPTIONS", "/graphql?query={me{name}}", ``, "application/json") assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, "OPTIONS, POST, HEAD", resp.Header().Get("Allow")) }) @@ -32,7 +32,7 @@ func TestOptions(t *testing.T) { t.Run("responds to head requests", func(t *testing.T) { h := testserver.New() h.AddTransport(transport.Options{}) - resp := doRequest(h, "HEAD", "/graphql?query={me{name}}", ``) + resp := doRequest(h, "HEAD", "/graphql?query={me{name}}", ``, "application/json") assert.Equal(t, http.StatusMethodNotAllowed, resp.Code) }) }