From 101842f73fb79b10c1299bb40506080e08543ec6 Mon Sep 17 00:00:00 2001 From: Alex Sonneveld Date: Sat, 12 Dec 2020 12:57:28 +1100 Subject: [PATCH] Update GQLgen test client to work with multipart form data Update the GQLgen to support multipart form data, like those present within the fileupload examples. - Add missing space between "unsupported encoding " and failing content-type header error --- client/client.go | 10 +++++++--- client/client_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/client/client.go b/client/client.go index 64367931e9..82d0dc87ac 100644 --- a/client/client.go +++ b/client/client.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "regexp" "github.com/mitchellh/mapstructure" ) @@ -119,15 +120,18 @@ func (p *Client) newRequest(query string, options ...Option) (*http.Request, err option(bd) } - switch bd.HTTP.Header.Get("Content-Type") { - case "application/json": + contentType := bd.HTTP.Header.Get("Content-Type") + switch { + case regexp.MustCompile(`multipart/form-data; ?boundary=.*`).MatchString(contentType): + break + case "application/json" == contentType: requestBody, err := json.Marshal(bd) if err != nil { return nil, fmt.Errorf("encode: %s", err.Error()) } bd.HTTP.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody)) default: - panic("unsupported encoding" + bd.HTTP.Header.Get("Content-Type")) + panic("unsupported encoding " + bd.HTTP.Header.Get("Content-Type")) } return bd.HTTP, nil diff --git a/client/client_test.go b/client/client_test.go index 64a75a30c6..be997171ec 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1,9 +1,12 @@ package client_test import ( + "bytes" "encoding/json" "io/ioutil" + "mime/multipart" "net/http" + "net/textproto" "testing" "github.com/99designs/gqlgen/client" @@ -39,6 +42,44 @@ func TestClient(t *testing.T) { require.Equal(t, "bob", resp.Name) } +func TestClientMultipartFormData(t *testing.T) { + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + bodyBytes, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + require.Contains(t, string(bodyBytes), `Content-Disposition: form-data; name="operations"`) + require.Contains(t, string(bodyBytes), `{"query":"mutation ($input: Input!) {}","variables":{"file":{}}`) + require.Contains(t, string(bodyBytes), `Content-Disposition: form-data; name="map"`) + require.Contains(t, string(bodyBytes), `{"0":["variables.file"]}`) + require.Contains(t, string(bodyBytes), `Content-Disposition: form-data; name="0"; filename="example.txt"`) + require.Contains(t, string(bodyBytes), `Content-Type: text/plain`) + require.Contains(t, string(bodyBytes), `Hello World`) + + w.Write([]byte(`{}`)) + }) + + c := client.New(h) + + var resp struct{} + c.MustPost("{ id }", &resp, + func(bd *client.Request) { + bodyBuf := &bytes.Buffer{} + bodyWriter := multipart.NewWriter(bodyBuf) + bodyWriter.WriteField("operations", `{"query":"mutation ($input: Input!) {}","variables":{"file":{}}`) + bodyWriter.WriteField("map", `{"0":["variables.file"]}`) + + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", `form-data; name="0"; filename="example.txt"`) + h.Set("Content-Type", "text/plain") + ff, _ := bodyWriter.CreatePart(h) + ff.Write([]byte("Hello World")) + bodyWriter.Close() + + bd.HTTP.Body = ioutil.NopCloser(bodyBuf) + bd.HTTP.Header.Set("Content-Type", bodyWriter.FormDataContentType()) + }, + ) +} + func TestAddHeader(t *testing.T) { h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, "ASDF", r.Header.Get("Test-Key"))